summaryrefslogtreecommitdiff
path: root/lib/Target/ARM
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2018-07-28 10:51:19 +0000
committerDimitry Andric <dim@FreeBSD.org>2018-07-28 10:51:19 +0000
commiteb11fae6d08f479c0799db45860a98af528fa6e7 (patch)
tree44d492a50c8c1a7eb8e2d17ea3360ec4d066f042 /lib/Target/ARM
parentb8a2042aa938069e862750553db0e4d82d25822c (diff)
Notes
Diffstat (limited to 'lib/Target/ARM')
-rw-r--r--lib/Target/ARM/A15SDOptimizer.cpp22
-rw-r--r--lib/Target/ARM/ARM.h7
-rw-r--r--lib/Target/ARM/ARM.td65
-rw-r--r--lib/Target/ARM/ARMAsmPrinter.cpp50
-rw-r--r--lib/Target/ARM/ARMAsmPrinter.h4
-rw-r--r--lib/Target/ARM/ARMBaseInstrInfo.cpp259
-rw-r--r--lib/Target/ARM/ARMBaseInstrInfo.h5
-rw-r--r--lib/Target/ARM/ARMBaseRegisterInfo.cpp8
-rw-r--r--lib/Target/ARM/ARMBaseRegisterInfo.h3
-rw-r--r--lib/Target/ARM/ARMCallLowering.cpp11
-rw-r--r--lib/Target/ARM/ARMCallingConv.h3
-rw-r--r--lib/Target/ARM/ARMCallingConv.td19
-rw-r--r--lib/Target/ARM/ARMCodeGenPrepare.cpp750
-rw-r--r--lib/Target/ARM/ARMComputeBlockSize.cpp1
-rw-r--r--lib/Target/ARM/ARMConstantIslandPass.cpp134
-rw-r--r--lib/Target/ARM/ARMConstantPoolValue.cpp1
-rw-r--r--lib/Target/ARM/ARMExpandPseudoInsts.cpp252
-rw-r--r--lib/Target/ARM/ARMFastISel.cpp11
-rw-r--r--lib/Target/ARM/ARMFrameLowering.cpp116
-rw-r--r--lib/Target/ARM/ARMFrameLowering.h2
-rw-r--r--lib/Target/ARM/ARMHazardRecognizer.cpp4
-rw-r--r--lib/Target/ARM/ARMISelDAGToDAG.cpp420
-rw-r--r--lib/Target/ARM/ARMISelLowering.cpp869
-rw-r--r--lib/Target/ARM/ARMISelLowering.h20
-rw-r--r--lib/Target/ARM/ARMInstrFormats.td9
-rw-r--r--lib/Target/ARM/ARMInstrInfo.cpp28
-rw-r--r--lib/Target/ARM/ARMInstrInfo.h7
-rw-r--r--lib/Target/ARM/ARMInstrInfo.td62
-rw-r--r--lib/Target/ARM/ARMInstrNEON.td314
-rw-r--r--lib/Target/ARM/ARMInstrThumb.td19
-rw-r--r--lib/Target/ARM/ARMInstrThumb2.td48
-rw-r--r--lib/Target/ARM/ARMInstrVFP.td235
-rw-r--r--lib/Target/ARM/ARMInstructionSelector.cpp128
-rw-r--r--lib/Target/ARM/ARMLegalizerInfo.cpp184
-rw-r--r--lib/Target/ARM/ARMLoadStoreOptimizer.cpp36
-rw-r--r--lib/Target/ARM/ARMMacroFusion.cpp65
-rw-r--r--lib/Target/ARM/ARMParallelDSP.cpp672
-rw-r--r--lib/Target/ARM/ARMRegisterBankInfo.cpp68
-rw-r--r--lib/Target/ARM/ARMRegisterBanks.td2
-rw-r--r--lib/Target/ARM/ARMRegisterInfo.td12
-rw-r--r--lib/Target/ARM/ARMScheduleA57.td41
-rw-r--r--lib/Target/ARM/ARMScheduleA9.td16
-rw-r--r--lib/Target/ARM/ARMScheduleR52.td45
-rw-r--r--lib/Target/ARM/ARMScheduleSwift.td37
-rw-r--r--lib/Target/ARM/ARMSubtarget.cpp2
-rw-r--r--lib/Target/ARM/ARMSubtarget.h41
-rw-r--r--lib/Target/ARM/ARMTargetMachine.cpp49
-rw-r--r--lib/Target/ARM/ARMTargetMachine.h10
-rw-r--r--lib/Target/ARM/ARMTargetObjectFile.cpp3
-rw-r--r--lib/Target/ARM/ARMTargetObjectFile.h5
-rw-r--r--lib/Target/ARM/ARMTargetTransformInfo.cpp30
-rw-r--r--lib/Target/ARM/AsmParser/ARMAsmParser.cpp532
-rw-r--r--lib/Target/ARM/CMakeLists.txt21
-rw-r--r--lib/Target/ARM/Disassembler/ARMDisassembler.cpp30
-rw-r--r--lib/Target/ARM/Disassembler/LLVMBuild.txt2
-rw-r--r--lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp16
-rw-r--r--lib/Target/ARM/InstPrinter/ARMInstPrinter.h2
-rw-r--r--lib/Target/ARM/LLVMBuild.txt2
-rw-r--r--lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp133
-rw-r--r--lib/Target/ARM/MCTargetDesc/ARMAsmBackend.h33
-rw-r--r--lib/Target/ARM/MCTargetDesc/ARMAsmBackendDarwin.h11
-rw-r--r--lib/Target/ARM/MCTargetDesc/ARMAsmBackendELF.h12
-rw-r--r--lib/Target/ARM/MCTargetDesc/ARMAsmBackendWinCOFF.h10
-rw-r--r--lib/Target/ARM/MCTargetDesc/ARMBaseInfo.h18
-rw-r--r--lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp8
-rw-r--r--lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp19
-rw-r--r--lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp2
-rw-r--r--lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.cpp50
-rw-r--r--lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.h41
-rw-r--r--lib/Target/ARM/MCTargetDesc/ARMMachObjectWriter.cpp10
-rw-r--r--lib/Target/ARM/MCTargetDesc/ARMWinCOFFObjectWriter.cpp7
-rw-r--r--lib/Target/ARM/MCTargetDesc/ARMWinCOFFStreamer.cpp15
-rw-r--r--lib/Target/ARM/MCTargetDesc/CMakeLists.txt1
-rw-r--r--lib/Target/ARM/MLxExpansionPass.cpp22
-rw-r--r--lib/Target/ARM/README.txt2
-rw-r--r--lib/Target/ARM/Thumb1FrameLowering.cpp19
-rw-r--r--lib/Target/ARM/Thumb1InstrInfo.cpp17
-rw-r--r--lib/Target/ARM/Thumb1InstrInfo.h1
-rw-r--r--lib/Target/ARM/Thumb2ITBlockPass.cpp4
-rw-r--r--lib/Target/ARM/Thumb2InstrInfo.cpp21
-rw-r--r--lib/Target/ARM/Thumb2SizeReduction.cpp14
-rw-r--r--lib/Target/ARM/ThumbRegisterInfo.cpp22
82 files changed, 4923 insertions, 1378 deletions
diff --git a/lib/Target/ARM/A15SDOptimizer.cpp b/lib/Target/ARM/A15SDOptimizer.cpp
index 16d5f74d19e3..be88fe4ddb14 100644
--- a/lib/Target/ARM/A15SDOptimizer.cpp
+++ b/lib/Target/ARM/A15SDOptimizer.cpp
@@ -180,7 +180,7 @@ void A15SDOptimizer::eraseInstrWithNoUses(MachineInstr *MI) {
SmallVector<MachineInstr *, 8> Front;
DeadInstr.insert(MI);
- DEBUG(dbgs() << "Deleting base instruction " << *MI << "\n");
+ LLVM_DEBUG(dbgs() << "Deleting base instruction " << *MI << "\n");
Front.push_back(MI);
while (Front.size() != 0) {
@@ -232,7 +232,7 @@ void A15SDOptimizer::eraseInstrWithNoUses(MachineInstr *MI) {
if (!IsDead) continue;
- DEBUG(dbgs() << "Deleting instruction " << *Def << "\n");
+ LLVM_DEBUG(dbgs() << "Deleting instruction " << *Def << "\n");
DeadInstr.insert(Def);
}
}
@@ -264,7 +264,7 @@ unsigned A15SDOptimizer::optimizeSDPattern(MachineInstr *MI) {
// Is it a subreg copy of ssub_0?
if (EC && EC->isCopy() &&
EC->getOperand(1).getSubReg() == ARM::ssub_0) {
- DEBUG(dbgs() << "Found a subreg copy: " << *SPRMI);
+ LLVM_DEBUG(dbgs() << "Found a subreg copy: " << *SPRMI);
// Find the thing we're subreg copying out of - is it of the same
// regclass as DPRMI? (i.e. a DPR or QPR).
@@ -272,8 +272,8 @@ unsigned A15SDOptimizer::optimizeSDPattern(MachineInstr *MI) {
const TargetRegisterClass *TRC =
MRI->getRegClass(MI->getOperand(1).getReg());
if (TRC->hasSuperClassEq(MRI->getRegClass(FullReg))) {
- DEBUG(dbgs() << "Subreg copy is compatible - returning ");
- DEBUG(dbgs() << printReg(FullReg) << "\n");
+ LLVM_DEBUG(dbgs() << "Subreg copy is compatible - returning ");
+ LLVM_DEBUG(dbgs() << printReg(FullReg) << "\n");
eraseInstrWithNoUses(MI);
return FullReg;
}
@@ -387,7 +387,7 @@ void A15SDOptimizer::elideCopiesAndPHIs(MachineInstr *MI,
continue;
Front.push_back(NewMI);
} else {
- DEBUG(dbgs() << "Found partial copy" << *MI <<"\n");
+ LLVM_DEBUG(dbgs() << "Found partial copy" << *MI << "\n");
Outs.push_back(MI);
}
}
@@ -642,9 +642,8 @@ bool A15SDOptimizer::runOnInstruction(MachineInstr *MI) {
// to find.
MRI->constrainRegClass(NewReg, MRI->getRegClass((*I)->getReg()));
- DEBUG(dbgs() << "Replacing operand "
- << **I << " with "
- << printReg(NewReg) << "\n");
+ LLVM_DEBUG(dbgs() << "Replacing operand " << **I << " with "
+ << printReg(NewReg) << "\n");
(*I)->substVirtReg(NewReg, 0, *TRI);
}
}
@@ -661,14 +660,15 @@ bool A15SDOptimizer::runOnMachineFunction(MachineFunction &Fn) {
const ARMSubtarget &STI = Fn.getSubtarget<ARMSubtarget>();
// Since the A15SDOptimizer pass can insert VDUP instructions, it can only be
// enabled when NEON is available.
- if (!(STI.isCortexA15() && STI.hasNEON()))
+ if (!(STI.useSplatVFPToNeon() && STI.hasNEON()))
return false;
+
TII = STI.getInstrInfo();
TRI = STI.getRegisterInfo();
MRI = &Fn.getRegInfo();
bool Modified = false;
- DEBUG(dbgs() << "Running on function " << Fn.getName()<< "\n");
+ LLVM_DEBUG(dbgs() << "Running on function " << Fn.getName() << "\n");
DeadInstr.clear();
Replacements.clear();
diff --git a/lib/Target/ARM/ARM.h b/lib/Target/ARM/ARM.h
index 9ffb4c2055f9..b5cc45c5cc94 100644
--- a/lib/Target/ARM/ARM.h
+++ b/lib/Target/ARM/ARM.h
@@ -15,6 +15,7 @@
#ifndef LLVM_LIB_TARGET_ARM_ARM_H
#define LLVM_LIB_TARGET_ARM_ARM_H
+#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Support/CodeGen.h"
#include <functional>
#include <vector>
@@ -35,11 +36,14 @@ class MachineInstr;
class MCInst;
class PassRegistry;
+
+Pass *createARMParallelDSPPass();
FunctionPass *createARMISelDag(ARMBaseTargetMachine &TM,
CodeGenOpt::Level OptLevel);
FunctionPass *createA15SDOptimizerPass();
FunctionPass *createARMLoadStoreOptimizationPass(bool PreAlloc = false);
FunctionPass *createARMExpandPseudoPass();
+FunctionPass *createARMCodeGenPreparePass();
FunctionPass *createARMConstantIslandPass();
FunctionPass *createMLxExpansionPass();
FunctionPass *createThumb2ITBlockPass();
@@ -57,8 +61,11 @@ void computeBlockSize(MachineFunction *MF, MachineBasicBlock *MBB,
BasicBlockInfo &BBI);
std::vector<BasicBlockInfo> computeAllBlockSizes(MachineFunction *MF);
+
+void initializeARMParallelDSPPass(PassRegistry &);
void initializeARMLoadStoreOptPass(PassRegistry &);
void initializeARMPreAllocLoadStoreOptPass(PassRegistry &);
+void initializeARMCodeGenPreparePass(PassRegistry &);
void initializeARMConstantIslandsPass(PassRegistry &);
void initializeARMExpandPseudoPass(PassRegistry &);
void initializeThumb2SizeReducePass(PassRegistry &);
diff --git a/lib/Target/ARM/ARM.td b/lib/Target/ARM/ARM.td
index c9766aa2161a..2e62a0790418 100644
--- a/lib/Target/ARM/ARM.td
+++ b/lib/Target/ARM/ARM.td
@@ -109,10 +109,16 @@ def Feature8MSecExt : SubtargetFeature<"8msecext", "Has8MSecExt", "true",
"Enable support for ARMv8-M "
"Security Extensions">;
+def FeatureSHA2 : SubtargetFeature<"sha2", "HasSHA2", "true",
+ "Enable SHA1 and SHA256 support", [FeatureNEON]>;
+
+def FeatureAES : SubtargetFeature<"aes", "HasAES", "true",
+ "Enable AES support", [FeatureNEON]>;
+
def FeatureCrypto : SubtargetFeature<"crypto", "HasCrypto", "true",
"Enable support for "
"Cryptography extensions",
- [FeatureNEON]>;
+ [FeatureNEON, FeatureSHA2, FeatureAES]>;
def FeatureCRC : SubtargetFeature<"crc", "HasCRC", "true",
"Enable support for CRC instructions">;
@@ -135,6 +141,10 @@ def FeatureFPAO : SubtargetFeature<"fpao", "HasFPAO", "true",
def FeatureFuseAES : SubtargetFeature<"fuse-aes", "HasFuseAES", "true",
"CPU fuses AES crypto operations">;
+// Fast execution of bottom and top halves of literal generation
+def FeatureFuseLiterals : SubtargetFeature<"fuse-literals", "HasFuseLiterals", "true",
+ "CPU fuses literal generation operations">;
+
// The way of reading thread pointer
def FeatureReadTp : SubtargetFeature<"read-tp-hard", "ReadTPHard", "true",
"Reading thread pointer from register">;
@@ -189,6 +199,13 @@ def FeatureDontWidenVMOVS : SubtargetFeature<"dont-widen-vmovs",
"DontWidenVMOVS", "true",
"Don't widen VMOVS to VMOVD">;
+// Some targets (e.g. Cortex-A15) prefer to avoid mixing operations on different
+// VFP register widths.
+def FeatureSplatVFPToNeon : SubtargetFeature<"splat-vfp-neon",
+ "SplatVFPToNeon", "true",
+ "Splat register from VFP to NEON",
+ [FeatureDontWidenVMOVS]>;
+
// Whether or not it is profitable to expand VFP/NEON MLA/MLS instructions.
def FeatureExpandMLx : SubtargetFeature<"expand-fp-mlx",
"ExpandMLx", "true",
@@ -330,6 +347,10 @@ def FeatureNoPostRASched : SubtargetFeature<"disable-postra-scheduler",
"DisablePostRAScheduler", "true",
"Don't schedule again after register allocation">;
+// Enable use of alias analysis during code generation
+def FeatureUseAA : SubtargetFeature<"use-aa", "UseAA", "true",
+ "Use alias analysis during codegen">;
+
//===----------------------------------------------------------------------===//
// ARM architecture class
//
@@ -415,6 +436,10 @@ def HasV8_3aOps : SubtargetFeature<"v8.3a", "HasV8_3aOps", "true",
"Support ARM v8.3a instructions",
[HasV8_2aOps]>;
+def HasV8_4aOps : SubtargetFeature<"v8.4a", "HasV8_4aOps", "true",
+ "Support ARM v8.4a instructions",
+ [HasV8_3aOps, FeatureDotProd]>;
+
//===----------------------------------------------------------------------===//
// ARM Processor subtarget features.
//
@@ -507,7 +532,8 @@ def ARMv5te : Architecture<"armv5te", "ARMv5te", [HasV5TEOps]>;
def ARMv5tej : Architecture<"armv5tej", "ARMv5tej", [HasV5TEOps]>;
-def ARMv6 : Architecture<"armv6", "ARMv6", [HasV6Ops]>;
+def ARMv6 : Architecture<"armv6", "ARMv6", [HasV6Ops,
+ FeatureDSP]>;
def ARMv6t2 : Architecture<"armv6t2", "ARMv6t2", [HasV6T2Ops,
FeatureDSP]>;
@@ -521,13 +547,15 @@ def ARMv6m : Architecture<"armv6-m", "ARMv6m", [HasV6MOps,
FeatureNoARM,
ModeThumb,
FeatureDB,
- FeatureMClass]>;
+ FeatureMClass,
+ FeatureStrictAlign]>;
def ARMv6sm : Architecture<"armv6s-m", "ARMv6sm", [HasV6MOps,
FeatureNoARM,
ModeThumb,
FeatureDB,
- FeatureMClass]>;
+ FeatureMClass,
+ FeatureStrictAlign]>;
def ARMv7a : Architecture<"armv7-a", "ARMv7a", [HasV7Ops,
FeatureNEON,
@@ -617,6 +645,20 @@ def ARMv83a : Architecture<"armv8.3-a", "ARMv83a", [HasV8_3aOps,
FeatureCRC,
FeatureRAS]>;
+def ARMv84a : Architecture<"armv8.4-a", "ARMv84a", [HasV8_4aOps,
+ FeatureAClass,
+ FeatureDB,
+ FeatureFPARMv8,
+ FeatureNEON,
+ FeatureDSP,
+ FeatureTrustZone,
+ FeatureMP,
+ FeatureVirtualization,
+ FeatureCrypto,
+ FeatureCRC,
+ FeatureRAS,
+ FeatureDotProd]>;
+
def ARMv8r : Architecture<"armv8-r", "ARMv8r", [HasV8Ops,
FeatureRClass,
FeatureDB,
@@ -637,7 +679,8 @@ def ARMv8mBaseline : Architecture<"armv8-m.base", "ARMv8mBaseline",
FeatureV7Clrex,
Feature8MSecExt,
FeatureAcquireRelease,
- FeatureMClass]>;
+ FeatureMClass,
+ FeatureStrictAlign]>;
def ARMv8mMainline : Architecture<"armv8-m.main", "ARMv8mMainline",
[HasV8MMainlineOps,
@@ -787,6 +830,7 @@ def : ProcessorModel<"cortex-a12", CortexA9Model, [ARMv7a, ProcA12,
def : ProcessorModel<"cortex-a15", CortexA9Model, [ARMv7a, ProcA15,
FeatureDontWidenVMOVS,
+ FeatureSplatVFPToNeon,
FeatureHasRetAddrStack,
FeatureMuxedUnits,
FeatureTrustZone,
@@ -991,6 +1035,12 @@ def : ProcNoItin<"exynos-m3", [ARMv8a, ProcExynosM1,
FeatureCrypto,
FeatureCRC]>;
+def : ProcNoItin<"exynos-m4", [ARMv8a, ProcExynosM1,
+ FeatureHWDivThumb,
+ FeatureHWDivARM,
+ FeatureCrypto,
+ FeatureCRC]>;
+
def : ProcNoItin<"kryo", [ARMv8a, ProcKryo,
FeatureHWDivThumb,
FeatureHWDivARM,
@@ -998,7 +1048,9 @@ def : ProcNoItin<"kryo", [ARMv8a, ProcKryo,
FeatureCRC]>;
def : ProcessorModel<"cortex-r52", CortexR52Model, [ARMv8r, ProcR52,
- FeatureFPAO]>;
+ FeatureUseMISched,
+ FeatureFPAO,
+ FeatureUseAA]>;
//===----------------------------------------------------------------------===//
// Register File Description
@@ -1042,4 +1094,5 @@ def ARM : Target {
let AssemblyWriters = [ARMAsmWriter];
let AssemblyParsers = [ARMAsmParser];
let AssemblyParserVariants = [ARMAsmParserVariant];
+ let AllowRegisterRenaming = 1;
}
diff --git a/lib/Target/ARM/ARMAsmPrinter.cpp b/lib/Target/ARM/ARMAsmPrinter.cpp
index d3d79fe975bb..2196f9b47f3b 100644
--- a/lib/Target/ARM/ARMAsmPrinter.cpp
+++ b/lib/Target/ARM/ARMAsmPrinter.cpp
@@ -235,6 +235,15 @@ void ARMAsmPrinter::printOperand(const MachineInstr *MI, int OpNum,
}
}
+MCSymbol *ARMAsmPrinter::GetCPISymbol(unsigned CPID) const {
+ // The AsmPrinter::GetCPISymbol superclass method tries to use CPID as
+ // indexes in MachineConstantPool, which isn't in sync with indexes used here.
+ const DataLayout &DL = getDataLayout();
+ return OutContext.getOrCreateSymbol(Twine(DL.getPrivateGlobalPrefix()) +
+ "CPI" + Twine(getFunctionNumber()) + "_" +
+ Twine(CPID));
+}
+
//===--------------------------------------------------------------------===//
MCSymbol *ARMAsmPrinter::
@@ -545,29 +554,6 @@ void ARMAsmPrinter::EmitEndOfAsmFile(Module &M) {
OutStreamer->EmitAssemblerFlag(MCAF_SubsectionsViaSymbols);
}
- if (TT.isOSBinFormatCOFF()) {
- const auto &TLOF =
- static_cast<const TargetLoweringObjectFileCOFF &>(getObjFileLowering());
-
- std::string Flags;
- raw_string_ostream OS(Flags);
-
- for (const auto &Function : M)
- TLOF.emitLinkerFlagsForGlobal(OS, &Function);
- for (const auto &Global : M.globals())
- TLOF.emitLinkerFlagsForGlobal(OS, &Global);
- for (const auto &Alias : M.aliases())
- TLOF.emitLinkerFlagsForGlobal(OS, &Alias);
-
- OS.flush();
-
- // Output collected flags
- if (!Flags.empty()) {
- OutStreamer->SwitchSection(TLOF.getDrectveSection());
- OutStreamer->EmitBytes(Flags);
- }
- }
-
// The last attribute to be emitted is ABI_optimization_goals
MCTargetStreamer &TS = *OutStreamer->getTargetStreamer();
ARMTargetStreamer &ATS = static_cast<ARMTargetStreamer &>(TS);
@@ -1086,6 +1072,8 @@ void ARMAsmPrinter::EmitUnwindingInstruction(const MachineInstr *MI) {
unsigned StartOp = 2 + 2;
// Use all the operands.
unsigned NumOffset = 0;
+ // Amount of SP adjustment folded into a push.
+ unsigned Pad = 0;
switch (Opc) {
default:
@@ -1107,6 +1095,16 @@ void ARMAsmPrinter::EmitUnwindingInstruction(const MachineInstr *MI) {
// temporary to workaround PR11902.
if (MO.isImplicit())
continue;
+ // Registers, pushed as a part of folding an SP update into the
+ // push instruction are marked as undef and should not be
+ // restored when unwinding, because the function can modify the
+ // corresponding stack slots.
+ if (MO.isUndef()) {
+ assert(RegList.empty() &&
+ "Pad registers must come before restored ones");
+ Pad += 4;
+ continue;
+ }
RegList.push_back(MO.getReg());
}
break;
@@ -1118,8 +1116,12 @@ void ARMAsmPrinter::EmitUnwindingInstruction(const MachineInstr *MI) {
RegList.push_back(SrcReg);
break;
}
- if (MAI->getExceptionHandlingType() == ExceptionHandling::ARM)
+ if (MAI->getExceptionHandlingType() == ExceptionHandling::ARM) {
ATS.emitRegSave(RegList, Opc == ARM::VSTMDDB_UPD);
+ // Account for the SP adjustment, folded into the push.
+ if (Pad)
+ ATS.emitPad(Pad);
+ }
} else {
// Changes of stack / frame pointer.
if (SrcReg == ARM::SP) {
diff --git a/lib/Target/ARM/ARMAsmPrinter.h b/lib/Target/ARM/ARMAsmPrinter.h
index 7b811b18f74a..0ba4bc05d6f7 100644
--- a/lib/Target/ARM/ARMAsmPrinter.h
+++ b/lib/Target/ARM/ARMAsmPrinter.h
@@ -101,7 +101,9 @@ public:
void EmitEndOfAsmFile(Module &M) override;
void EmitXXStructor(const DataLayout &DL, const Constant *CV) override;
void EmitGlobalVariable(const GlobalVariable *GV) override;
-
+
+ MCSymbol *GetCPISymbol(unsigned CPID) const override;
+
// lowerOperand - Convert a MachineOperand into the equivalent MCOperand.
bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp);
diff --git a/lib/Target/ARM/ARMBaseInstrInfo.cpp b/lib/Target/ARM/ARMBaseInstrInfo.cpp
index 8c1727724a9e..b1c2031c7d7b 100644
--- a/lib/Target/ARM/ARMBaseInstrInfo.cpp
+++ b/lib/Target/ARM/ARMBaseInstrInfo.cpp
@@ -331,7 +331,7 @@ bool ARMBaseInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
bool CantAnalyze = false;
// Skip over DEBUG values and predicated nonterminators.
- while (I->isDebugValue() || !I->isTerminator()) {
+ while (I->isDebugInstr() || !I->isTerminator()) {
if (I == MBB.begin())
return false;
--I;
@@ -935,6 +935,25 @@ void ARMBaseInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
Mov->addRegisterKilled(SrcReg, TRI);
}
+bool ARMBaseInstrInfo::isCopyInstr(const MachineInstr &MI,
+ const MachineOperand *&Src,
+ const MachineOperand *&Dest) const {
+ // VMOVRRD is also a copy instruction but it requires
+ // special way of handling. It is more complex copy version
+ // and since that we are not considering it. For recognition
+ // of such instruction isExtractSubregLike MI interface fuction
+ // could be used.
+ // VORRq is considered as a move only if two inputs are
+ // the same register.
+ if (!MI.isMoveReg() ||
+ (MI.getOpcode() == ARM::VORRq &&
+ MI.getOperand(1).getReg() != MI.getOperand(2).getReg()))
+ return false;
+ Dest = &MI.getOperand(0);
+ Src = &MI.getOperand(1);
+ return true;
+}
+
const MachineInstrBuilder &
ARMBaseInstrInfo::AddDReg(MachineInstrBuilder &MIB, unsigned Reg,
unsigned SubIdx, unsigned State,
@@ -963,6 +982,17 @@ storeRegToStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
MFI.getObjectSize(FI), Align);
switch (TRI->getSpillSize(*RC)) {
+ case 2:
+ if (ARM::HPRRegClass.hasSubClassEq(RC)) {
+ BuildMI(MBB, I, DL, get(ARM::VSTRH))
+ .addReg(SrcReg, getKillRegState(isKill))
+ .addFrameIndex(FI)
+ .addImm(0)
+ .addMemOperand(MMO)
+ .add(predOps(ARMCC::AL));
+ } else
+ llvm_unreachable("Unknown reg class!");
+ break;
case 4:
if (ARM::GPRRegClass.hasSubClassEq(RC)) {
BuildMI(MBB, I, DL, get(ARM::STRi12))
@@ -1161,6 +1191,16 @@ loadRegFromStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
MFI.getObjectSize(FI), Align);
switch (TRI->getSpillSize(*RC)) {
+ case 2:
+ if (ARM::HPRRegClass.hasSubClassEq(RC)) {
+ BuildMI(MBB, I, DL, get(ARM::VLDRH), DestReg)
+ .addFrameIndex(FI)
+ .addImm(0)
+ .addMemOperand(MMO)
+ .add(predOps(ARMCC::AL));
+ } else
+ llvm_unreachable("Unknown reg class!");
+ break;
case 4:
if (ARM::GPRRegClass.hasSubClassEq(RC)) {
BuildMI(MBB, I, DL, get(ARM::LDRi12), DestReg)
@@ -1168,7 +1208,6 @@ loadRegFromStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
.addImm(0)
.addMemOperand(MMO)
.add(predOps(ARMCC::AL));
-
} else if (ARM::SPRRegClass.hasSubClassEq(RC)) {
BuildMI(MBB, I, DL, get(ARM::VLDRS), DestReg)
.addFrameIndex(FI)
@@ -1321,7 +1360,13 @@ unsigned ARMBaseInstrInfo::isLoadFromStackSlot(const MachineInstr &MI,
}
break;
case ARM::VLD1q64:
+ case ARM::VLD1d8TPseudo:
+ case ARM::VLD1d16TPseudo:
+ case ARM::VLD1d32TPseudo:
case ARM::VLD1d64TPseudo:
+ case ARM::VLD1d8QPseudo:
+ case ARM::VLD1d16QPseudo:
+ case ARM::VLD1d32QPseudo:
case ARM::VLD1d64QPseudo:
if (MI.getOperand(1).isFI() && MI.getOperand(0).getSubReg() == 0) {
FrameIndex = MI.getOperand(1).getIndex();
@@ -1345,7 +1390,7 @@ unsigned ARMBaseInstrInfo::isLoadFromStackSlotPostFE(const MachineInstr &MI,
return MI.mayLoad() && hasLoadFromStackSlot(MI, Dummy, FrameIndex);
}
-/// \brief Expands MEMCPY to either LDMIA/STMIA or LDMIA_UPD/STMID_UPD
+/// Expands MEMCPY to either LDMIA/STMIA or LDMIA_UPD/STMID_UPD
/// depending on whether the result is used.
void ARMBaseInstrInfo::expandMEMCPY(MachineBasicBlock::iterator MI) const {
bool isThumb1 = Subtarget.isThumb1Only();
@@ -1358,7 +1403,6 @@ void ARMBaseInstrInfo::expandMEMCPY(MachineBasicBlock::iterator MI) const {
MachineInstrBuilder LDM, STM;
if (isThumb1 || !MI->getOperand(1).isDead()) {
MachineOperand LDWb(MI->getOperand(1));
- LDWb.setIsRenamable(false);
LDM = BuildMI(*BB, MI, dl, TII->get(isThumb2 ? ARM::t2LDMIA_UPD
: isThumb1 ? ARM::tLDMIA_UPD
: ARM::LDMIA_UPD))
@@ -1369,7 +1413,6 @@ void ARMBaseInstrInfo::expandMEMCPY(MachineBasicBlock::iterator MI) const {
if (isThumb1 || !MI->getOperand(0).isDead()) {
MachineOperand STWb(MI->getOperand(0));
- STWb.setIsRenamable(false);
STM = BuildMI(*BB, MI, dl, TII->get(isThumb2 ? ARM::t2STMIA_UPD
: isThumb1 ? ARM::tSTMIA_UPD
: ARM::STMIA_UPD))
@@ -1379,11 +1422,9 @@ void ARMBaseInstrInfo::expandMEMCPY(MachineBasicBlock::iterator MI) const {
}
MachineOperand LDBase(MI->getOperand(3));
- LDBase.setIsRenamable(false);
LDM.add(LDBase).add(predOps(ARMCC::AL));
MachineOperand STBase(MI->getOperand(2));
- STBase.setIsRenamable(false);
STM.add(STBase).add(predOps(ARMCC::AL));
// Sort the scratch registers into ascending order.
@@ -1391,12 +1432,12 @@ void ARMBaseInstrInfo::expandMEMCPY(MachineBasicBlock::iterator MI) const {
SmallVector<unsigned, 6> ScratchRegs;
for(unsigned I = 5; I < MI->getNumOperands(); ++I)
ScratchRegs.push_back(MI->getOperand(I).getReg());
- std::sort(ScratchRegs.begin(), ScratchRegs.end(),
- [&TRI](const unsigned &Reg1,
- const unsigned &Reg2) -> bool {
- return TRI.getEncodingValue(Reg1) <
- TRI.getEncodingValue(Reg2);
- });
+ llvm::sort(ScratchRegs.begin(), ScratchRegs.end(),
+ [&TRI](const unsigned &Reg1,
+ const unsigned &Reg2) -> bool {
+ return TRI.getEncodingValue(Reg1) <
+ TRI.getEncodingValue(Reg2);
+ });
for (const auto &Reg : ScratchRegs) {
LDM.addReg(Reg, RegState::Define);
@@ -1453,7 +1494,7 @@ bool ARMBaseInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
return false;
// All clear, widen the COPY.
- DEBUG(dbgs() << "widening: " << MI);
+ LLVM_DEBUG(dbgs() << "widening: " << MI);
MachineInstrBuilder MIB(*MI.getParent()->getParent(), MI);
// Get rid of the old implicit-def of DstRegD. Leave it if it defines a Q-reg
@@ -1482,7 +1523,7 @@ bool ARMBaseInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
MI.addRegisterKilled(SrcRegS, TRI, true);
}
- DEBUG(dbgs() << "replaced by: " << MI);
+ LLVM_DEBUG(dbgs() << "replaced by: " << MI);
return true;
}
@@ -1659,7 +1700,7 @@ bool ARMBaseInstrInfo::produceSameValue(const MachineInstr &MI0,
}
for (unsigned i = 3, e = MI0.getNumOperands(); i != e; ++i) {
- // %12 = PICLDR %11, 0, pred:14, pred:%noreg
+ // %12 = PICLDR %11, 0, 14, %noreg
const MachineOperand &MO0 = MI0.getOperand(i);
const MachineOperand &MO1 = MI1.getOperand(i);
if (!MO0.isIdenticalTo(MO1))
@@ -1799,7 +1840,7 @@ bool ARMBaseInstrInfo::isSchedulingBoundary(const MachineInstr &MI,
// considered a scheduling hazard, which is wrong. It should be the actual
// instruction preceding the dbg_value instruction(s), just like it is
// when debug info is not present.
- if (MI.isDebugValue())
+ if (MI.isDebugInstr())
return false;
// Terminators and labels can't be scheduled around.
@@ -1813,8 +1854,8 @@ bool ARMBaseInstrInfo::isSchedulingBoundary(const MachineInstr &MI,
// to the t2IT instruction. The added compile time and complexity does not
// seem worth it.
MachineBasicBlock::const_iterator I = MI;
- // Make sure to skip any dbg_value instructions
- while (++I != MBB->end() && I->isDebugValue())
+ // Make sure to skip any debug instructions
+ while (++I != MBB->end() && I->isDebugInstr())
;
if (I != MBB->end() && I->getOpcode() == ARM::t2IT)
return true;
@@ -2277,9 +2318,9 @@ bool llvm::tryFoldSPUpdateIntoPushPop(const ARMSubtarget &Subtarget,
--CurRegEnc) {
unsigned CurReg = RegClass->getRegister(CurRegEnc);
if (!IsPop) {
- // Pushing any register is completely harmless, mark the
- // register involved as undef since we don't care about it in
- // the slightest.
+ // Pushing any register is completely harmless, mark the register involved
+ // as undef since we don't care about its value and must not restore it
+ // during stack unwinding.
RegList.push_back(MachineOperand::CreateReg(CurReg, false, false,
false, false, true));
--RegsNeeded;
@@ -2409,6 +2450,14 @@ bool llvm::rewriteARMFrameIndex(MachineInstr &MI, unsigned FrameRegIdx,
NumBits = 8;
Scale = 4;
break;
+ case ARMII::AddrMode5FP16:
+ ImmIdx = FrameRegIdx+1;
+ InstrOffs = ARM_AM::getAM5Offset(MI.getOperand(ImmIdx).getImm());
+ if (ARM_AM::getAM5Op(MI.getOperand(ImmIdx).getImm()) == ARM_AM::sub)
+ InstrOffs *= -1;
+ NumBits = 8;
+ Scale = 2;
+ break;
default:
llvm_unreachable("Unsupported addressing mode!");
}
@@ -2534,14 +2583,28 @@ inline static ARMCC::CondCodes getSwappedCondition(ARMCC::CondCodes CC) {
}
}
+/// getCmpToAddCondition - assume the flags are set by CMP(a,b), return
+/// the condition code if we modify the instructions such that flags are
+/// set by ADD(a,b,X).
+inline static ARMCC::CondCodes getCmpToAddCondition(ARMCC::CondCodes CC) {
+ switch (CC) {
+ default: return ARMCC::AL;
+ case ARMCC::HS: return ARMCC::LO;
+ case ARMCC::LO: return ARMCC::HS;
+ case ARMCC::VS: return ARMCC::VS;
+ case ARMCC::VC: return ARMCC::VC;
+ }
+}
+
/// isRedundantFlagInstr - check whether the first instruction, whose only
/// purpose is to update flags, can be made redundant.
/// CMPrr can be made redundant by SUBrr if the operands are the same.
/// CMPri can be made redundant by SUBri if the operands are the same.
+/// CMPrr(r0, r1) can be made redundant by ADDr[ri](r0, r1, X).
/// This function can be extended later on.
-inline static bool isRedundantFlagInstr(MachineInstr *CmpI, unsigned SrcReg,
- unsigned SrcReg2, int ImmValue,
- MachineInstr *OI) {
+inline static bool isRedundantFlagInstr(const MachineInstr *CmpI,
+ unsigned SrcReg, unsigned SrcReg2,
+ int ImmValue, const MachineInstr *OI) {
if ((CmpI->getOpcode() == ARM::CMPrr ||
CmpI->getOpcode() == ARM::t2CMPrr) &&
(OI->getOpcode() == ARM::SUBrr ||
@@ -2559,6 +2622,14 @@ inline static bool isRedundantFlagInstr(MachineInstr *CmpI, unsigned SrcReg,
OI->getOperand(1).getReg() == SrcReg &&
OI->getOperand(2).getImm() == ImmValue)
return true;
+
+ if ((CmpI->getOpcode() == ARM::CMPrr || CmpI->getOpcode() == ARM::t2CMPrr) &&
+ (OI->getOpcode() == ARM::ADDrr || OI->getOpcode() == ARM::t2ADDrr ||
+ OI->getOpcode() == ARM::ADDri || OI->getOpcode() == ARM::t2ADDri) &&
+ OI->getOperand(0).isReg() && OI->getOperand(1).isReg() &&
+ OI->getOperand(0).getReg() == SrcReg &&
+ OI->getOperand(1).getReg() == SrcReg2)
+ return true;
return false;
}
@@ -2661,17 +2732,18 @@ bool ARMBaseInstrInfo::optimizeCompareInstr(
if (I == B) return false;
// There are two possible candidates which can be changed to set CPSR:
- // One is MI, the other is a SUB instruction.
- // For CMPrr(r1,r2), we are looking for SUB(r1,r2) or SUB(r2,r1).
+ // One is MI, the other is a SUB or ADD instruction.
+ // For CMPrr(r1,r2), we are looking for SUB(r1,r2), SUB(r2,r1), or
+ // ADDr[ri](r1, r2, X).
// For CMPri(r1, CmpValue), we are looking for SUBri(r1, CmpValue).
- MachineInstr *Sub = nullptr;
+ MachineInstr *SubAdd = nullptr;
if (SrcReg2 != 0)
// MI is not a candidate for CMPrr.
MI = nullptr;
else if (MI->getParent() != CmpInstr.getParent() || CmpValue != 0) {
// Conservatively refuse to convert an instruction which isn't in the same
// BB as the comparison.
- // For CMPri w/ CmpValue != 0, a Sub may still be a candidate.
+ // For CMPri w/ CmpValue != 0, a SubAdd may still be a candidate.
// Thus we cannot return here.
if (CmpInstr.getOpcode() == ARM::CMPri ||
CmpInstr.getOpcode() == ARM::t2CMPri)
@@ -2716,11 +2788,20 @@ bool ARMBaseInstrInfo::optimizeCompareInstr(
}
// Check that CPSR isn't set between the comparison instruction and the one we
- // want to change. At the same time, search for Sub.
+ // want to change. At the same time, search for SubAdd.
const TargetRegisterInfo *TRI = &getRegisterInfo();
- --I;
- for (; I != E; --I) {
- const MachineInstr &Instr = *I;
+ do {
+ const MachineInstr &Instr = *--I;
+
+ // Check whether CmpInstr can be made redundant by the current instruction.
+ if (isRedundantFlagInstr(&CmpInstr, SrcReg, SrcReg2, CmpValue, &Instr)) {
+ SubAdd = &*I;
+ break;
+ }
+
+ // Allow E (which was initially MI) to be SubAdd but do not search before E.
+ if (I == E)
+ break;
if (Instr.modifiesRegister(ARM::CPSR, TRI) ||
Instr.readsRegister(ARM::CPSR, TRI))
@@ -2728,23 +2809,14 @@ bool ARMBaseInstrInfo::optimizeCompareInstr(
// change. We can't do this transformation.
return false;
- // Check whether CmpInstr can be made redundant by the current instruction.
- if (isRedundantFlagInstr(&CmpInstr, SrcReg, SrcReg2, CmpValue, &*I)) {
- Sub = &*I;
- break;
- }
-
- if (I == B)
- // The 'and' is below the comparison instruction.
- return false;
- }
+ } while (I != B);
// Return false if no candidates exist.
- if (!MI && !Sub)
+ if (!MI && !SubAdd)
return false;
// The single candidate is called MI.
- if (!MI) MI = Sub;
+ if (!MI) MI = SubAdd;
// We can't use a predicated instruction - it doesn't always write the flags.
if (isPredicated(*MI))
@@ -2802,25 +2874,31 @@ bool ARMBaseInstrInfo::optimizeCompareInstr(
break;
}
- if (Sub) {
- ARMCC::CondCodes NewCC = getSwappedCondition(CC);
- if (NewCC == ARMCC::AL)
- return false;
+ if (SubAdd) {
// If we have SUB(r1, r2) and CMP(r2, r1), the condition code based
// on CMP needs to be updated to be based on SUB.
+ // If we have ADD(r1, r2, X) and CMP(r1, r2), the condition code also
+ // needs to be modified.
// Push the condition code operands to OperandsToUpdate.
// If it is safe to remove CmpInstr, the condition code of these
// operands will be modified.
- if (SrcReg2 != 0 && Sub->getOperand(1).getReg() == SrcReg2 &&
- Sub->getOperand(2).getReg() == SrcReg) {
+ unsigned Opc = SubAdd->getOpcode();
+ bool IsSub = Opc == ARM::SUBrr || Opc == ARM::t2SUBrr ||
+ Opc == ARM::SUBri || Opc == ARM::t2SUBri;
+ if (!IsSub || (SrcReg2 != 0 && SubAdd->getOperand(1).getReg() == SrcReg2 &&
+ SubAdd->getOperand(2).getReg() == SrcReg)) {
// VSel doesn't support condition code update.
if (IsInstrVSel)
return false;
+ // Ensure we can swap the condition.
+ ARMCC::CondCodes NewCC = (IsSub ? getSwappedCondition(CC) : getCmpToAddCondition(CC));
+ if (NewCC == ARMCC::AL)
+ return false;
OperandsToUpdate.push_back(
std::make_pair(&((*I).getOperand(IO - 1)), NewCC));
}
} else {
- // No Sub, so this is x = <op> y, z; cmp x, 0.
+ // No SubAdd, so this is x = <op> y, z; cmp x, 0.
switch (CC) {
case ARMCC::EQ: // Z
case ARMCC::NE: // Z
@@ -2874,6 +2952,23 @@ bool ARMBaseInstrInfo::optimizeCompareInstr(
return true;
}
+bool ARMBaseInstrInfo::shouldSink(const MachineInstr &MI) const {
+ // Do not sink MI if it might be used to optimize a redundant compare.
+ // We heuristically only look at the instruction immediately following MI to
+ // avoid potentially searching the entire basic block.
+ if (isPredicated(MI))
+ return true;
+ MachineBasicBlock::const_iterator Next = &MI;
+ ++Next;
+ unsigned SrcReg, SrcReg2;
+ int CmpMask, CmpValue;
+ if (Next != MI.getParent()->end() &&
+ analyzeCompare(*Next, SrcReg, SrcReg2, CmpMask, CmpValue) &&
+ isRedundantFlagInstr(&*Next, SrcReg, SrcReg2, CmpValue, &MI))
+ return false;
+ return true;
+}
+
bool ARMBaseInstrInfo::FoldImmediate(MachineInstr &UseMI, MachineInstr &DefMI,
unsigned Reg,
MachineRegisterInfo *MRI) const {
@@ -3467,8 +3562,8 @@ bool ARMBaseInstrInfo::isLDMBaseRegInList(const MachineInstr &MI) const {
}
unsigned
ARMBaseInstrInfo::getLDMVariableDefsSize(const MachineInstr &MI) const {
- // ins GPR:$Rn, pred:$p (2xOp), reglist:$regs, variable_ops
- // (outs GPR:$wb), (ins GPR:$Rn, pred:$p (2xOp), reglist:$regs, variable_ops)
+ // ins GPR:$Rn, $p (2xOp), reglist:$regs, variable_ops
+ // (outs GPR:$wb), (ins GPR:$Rn, $p (2xOp), reglist:$regs, variable_ops)
return MI.getNumOperands() + 1 - MI.getDesc().getNumOperands();
}
@@ -4142,8 +4237,12 @@ ARMBaseInstrInfo::getOperandLatency(const InstrItineraryData *ItinData,
case ARM::VLD3d8Pseudo:
case ARM::VLD3d16Pseudo:
case ARM::VLD3d32Pseudo:
+ case ARM::VLD1d8TPseudo:
+ case ARM::VLD1d16TPseudo:
+ case ARM::VLD1d32TPseudo:
case ARM::VLD1d64TPseudo:
case ARM::VLD1d64TPseudoWB_fixed:
+ case ARM::VLD1d64TPseudoWB_register:
case ARM::VLD3d8Pseudo_UPD:
case ARM::VLD3d16Pseudo_UPD:
case ARM::VLD3d32Pseudo_UPD:
@@ -4159,8 +4258,28 @@ ARMBaseInstrInfo::getOperandLatency(const InstrItineraryData *ItinData,
case ARM::VLD4d8Pseudo:
case ARM::VLD4d16Pseudo:
case ARM::VLD4d32Pseudo:
+ case ARM::VLD1d8QPseudo:
+ case ARM::VLD1d16QPseudo:
+ case ARM::VLD1d32QPseudo:
case ARM::VLD1d64QPseudo:
case ARM::VLD1d64QPseudoWB_fixed:
+ case ARM::VLD1d64QPseudoWB_register:
+ case ARM::VLD1q8HighQPseudo:
+ case ARM::VLD1q8LowQPseudo_UPD:
+ case ARM::VLD1q8HighTPseudo:
+ case ARM::VLD1q8LowTPseudo_UPD:
+ case ARM::VLD1q16HighQPseudo:
+ case ARM::VLD1q16LowQPseudo_UPD:
+ case ARM::VLD1q16HighTPseudo:
+ case ARM::VLD1q16LowTPseudo_UPD:
+ case ARM::VLD1q32HighQPseudo:
+ case ARM::VLD1q32LowQPseudo_UPD:
+ case ARM::VLD1q32HighTPseudo:
+ case ARM::VLD1q32LowTPseudo_UPD:
+ case ARM::VLD1q64HighQPseudo:
+ case ARM::VLD1q64LowQPseudo_UPD:
+ case ARM::VLD1q64HighTPseudo:
+ case ARM::VLD1q64LowTPseudo_UPD:
case ARM::VLD4d8Pseudo_UPD:
case ARM::VLD4d16Pseudo_UPD:
case ARM::VLD4d32Pseudo_UPD:
@@ -4191,12 +4310,30 @@ ARMBaseInstrInfo::getOperandLatency(const InstrItineraryData *ItinData,
case ARM::VLD2DUPd8wb_register:
case ARM::VLD2DUPd16wb_register:
case ARM::VLD2DUPd32wb_register:
+ case ARM::VLD2DUPq8EvenPseudo:
+ case ARM::VLD2DUPq8OddPseudo:
+ case ARM::VLD2DUPq16EvenPseudo:
+ case ARM::VLD2DUPq16OddPseudo:
+ case ARM::VLD2DUPq32EvenPseudo:
+ case ARM::VLD2DUPq32OddPseudo:
+ case ARM::VLD3DUPq8EvenPseudo:
+ case ARM::VLD3DUPq8OddPseudo:
+ case ARM::VLD3DUPq16EvenPseudo:
+ case ARM::VLD3DUPq16OddPseudo:
+ case ARM::VLD3DUPq32EvenPseudo:
+ case ARM::VLD3DUPq32OddPseudo:
case ARM::VLD4DUPd8Pseudo:
case ARM::VLD4DUPd16Pseudo:
case ARM::VLD4DUPd32Pseudo:
case ARM::VLD4DUPd8Pseudo_UPD:
case ARM::VLD4DUPd16Pseudo_UPD:
case ARM::VLD4DUPd32Pseudo_UPD:
+ case ARM::VLD4DUPq8EvenPseudo:
+ case ARM::VLD4DUPq8OddPseudo:
+ case ARM::VLD4DUPq16EvenPseudo:
+ case ARM::VLD4DUPq16OddPseudo:
+ case ARM::VLD4DUPq32EvenPseudo:
+ case ARM::VLD4DUPq32OddPseudo:
case ARM::VLD1LNq8Pseudo:
case ARM::VLD1LNq16Pseudo:
case ARM::VLD1LNq32Pseudo:
@@ -4864,12 +5001,14 @@ bool ARMBaseInstrInfo::getRegSequenceLikeInputs(
// Populate the InputRegs accordingly.
// rY
const MachineOperand *MOReg = &MI.getOperand(1);
- InputRegs.push_back(
- RegSubRegPairAndIdx(MOReg->getReg(), MOReg->getSubReg(), ARM::ssub_0));
+ if (!MOReg->isUndef())
+ InputRegs.push_back(RegSubRegPairAndIdx(MOReg->getReg(),
+ MOReg->getSubReg(), ARM::ssub_0));
// rZ
MOReg = &MI.getOperand(2);
- InputRegs.push_back(
- RegSubRegPairAndIdx(MOReg->getReg(), MOReg->getSubReg(), ARM::ssub_1));
+ if (!MOReg->isUndef())
+ InputRegs.push_back(RegSubRegPairAndIdx(MOReg->getReg(),
+ MOReg->getSubReg(), ARM::ssub_1));
return true;
}
llvm_unreachable("Target dependent opcode missing");
@@ -4888,6 +5027,8 @@ bool ARMBaseInstrInfo::getExtractSubregLikeInputs(
// rX = EXTRACT_SUBREG dZ, ssub_0
// rY = EXTRACT_SUBREG dZ, ssub_1
const MachineOperand &MOReg = MI.getOperand(2);
+ if (MOReg.isUndef())
+ return false;
InputReg.Reg = MOReg.getReg();
InputReg.SubReg = MOReg.getSubReg();
InputReg.SubIdx = DefIdx == 0 ? ARM::ssub_0 : ARM::ssub_1;
@@ -4907,6 +5048,8 @@ bool ARMBaseInstrInfo::getInsertSubregLikeInputs(
// dX = VSETLNi32 dY, rZ, imm
const MachineOperand &MOBaseReg = MI.getOperand(1);
const MachineOperand &MOInsertedReg = MI.getOperand(2);
+ if (MOInsertedReg.isUndef())
+ return false;
const MachineOperand &MOIndex = MI.getOperand(3);
BaseReg.Reg = MOBaseReg.getReg();
BaseReg.SubReg = MOBaseReg.getSubReg();
diff --git a/lib/Target/ARM/ARMBaseInstrInfo.h b/lib/Target/ARM/ARMBaseInstrInfo.h
index d375f40d6e14..b54be15097b1 100644
--- a/lib/Target/ARM/ARMBaseInstrInfo.h
+++ b/lib/Target/ARM/ARMBaseInstrInfo.h
@@ -201,6 +201,9 @@ public:
const DebugLoc &DL, unsigned DestReg, unsigned SrcReg,
bool KillSrc) const override;
+ bool isCopyInstr(const MachineInstr &MI, const MachineOperand *&Src,
+ const MachineOperand *&Dest) const override;
+
void storeRegToStackSlot(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI,
unsigned SrcReg, bool isKill, int FrameIndex,
@@ -215,6 +218,8 @@ public:
bool expandPostRAPseudo(MachineInstr &MI) const override;
+ bool shouldSink(const MachineInstr &MI) const override;
+
void reMaterialize(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
unsigned DestReg, unsigned SubIdx,
const MachineInstr &Orig,
diff --git a/lib/Target/ARM/ARMBaseRegisterInfo.cpp b/lib/Target/ARM/ARMBaseRegisterInfo.cpp
index 4b9a4376adf8..43e8b7d66c62 100644
--- a/lib/Target/ARM/ARMBaseRegisterInfo.cpp
+++ b/lib/Target/ARM/ARMBaseRegisterInfo.cpp
@@ -838,10 +838,10 @@ bool ARMBaseRegisterInfo::shouldCoalesce(MachineInstr *MI,
auto AFI = MF->getInfo<ARMFunctionInfo>();
auto It = AFI->getCoalescedWeight(MBB);
- DEBUG(dbgs() << "\tARM::shouldCoalesce - Coalesced Weight: "
- << It->second << "\n");
- DEBUG(dbgs() << "\tARM::shouldCoalesce - Reg Weight: "
- << NewRCWeight.RegWeight << "\n");
+ LLVM_DEBUG(dbgs() << "\tARM::shouldCoalesce - Coalesced Weight: "
+ << It->second << "\n");
+ LLVM_DEBUG(dbgs() << "\tARM::shouldCoalesce - Reg Weight: "
+ << NewRCWeight.RegWeight << "\n");
// This number is the largest round number that which meets the criteria:
// (1) addresses PR18825
diff --git a/lib/Target/ARM/ARMBaseRegisterInfo.h b/lib/Target/ARM/ARMBaseRegisterInfo.h
index 5801e6bdbd0e..f755f66a0f3a 100644
--- a/lib/Target/ARM/ARMBaseRegisterInfo.h
+++ b/lib/Target/ARM/ARMBaseRegisterInfo.h
@@ -154,6 +154,7 @@ public:
void updateRegAllocHint(unsigned Reg, unsigned NewReg,
MachineFunction &MF) const override;
+ bool enableMultipleCopyHints() const override { return true; }
bool hasBasePointer(const MachineFunction &MF) const;
@@ -200,7 +201,7 @@ public:
int SPAdj, unsigned FIOperandNum,
RegScavenger *RS = nullptr) const override;
- /// \brief SrcRC and DstRC will be morphed into NewRC if this returns true
+ /// SrcRC and DstRC will be morphed into NewRC if this returns true
bool shouldCoalesce(MachineInstr *MI,
const TargetRegisterClass *SrcRC,
unsigned SubReg,
diff --git a/lib/Target/ARM/ARMCallLowering.cpp b/lib/Target/ARM/ARMCallLowering.cpp
index eab4b3b13f31..47f998b696f5 100644
--- a/lib/Target/ARM/ARMCallLowering.cpp
+++ b/lib/Target/ARM/ARMCallLowering.cpp
@@ -31,7 +31,6 @@
#include "llvm/CodeGen/MachineMemOperand.h"
#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
-#include "llvm/CodeGen/MachineValueType.h"
#include "llvm/CodeGen/TargetRegisterInfo.h"
#include "llvm/CodeGen/TargetSubtargetInfo.h"
#include "llvm/CodeGen/ValueTypes.h"
@@ -43,6 +42,7 @@
#include "llvm/IR/Value.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/LowLevelTypeImpl.h"
+#include "llvm/Support/MachineValueType.h"
#include <algorithm>
#include <cassert>
#include <cstdint>
@@ -469,7 +469,12 @@ bool ARMCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
if (!MBB.empty())
MIRBuilder.setInstr(*MBB.begin());
- return handleAssignments(MIRBuilder, ArgInfos, ArgHandler);
+ if (!handleAssignments(MIRBuilder, ArgInfos, ArgHandler))
+ return false;
+
+ // Move back to the end of the basic block.
+ MIRBuilder.setMBB(MBB);
+ return true;
}
namespace {
@@ -521,7 +526,7 @@ bool ARMCallLowering::lowerCall(MachineIRBuilder &MIRBuilder,
if (CalleeReg && !TRI->isPhysicalRegister(CalleeReg))
MIB->getOperand(0).setReg(constrainOperandRegClass(
MF, *TRI, MRI, *STI.getInstrInfo(), *STI.getRegBankInfo(),
- *MIB.getInstr(), MIB->getDesc(), CalleeReg, 0));
+ *MIB.getInstr(), MIB->getDesc(), Callee, 0));
}
SmallVector<ArgInfo, 8> ArgInfos;
diff --git a/lib/Target/ARM/ARMCallingConv.h b/lib/Target/ARM/ARMCallingConv.h
index 284b67fd59b6..63bf48abb7ac 100644
--- a/lib/Target/ARM/ARMCallingConv.h
+++ b/lib/Target/ARM/ARMCallingConv.h
@@ -217,12 +217,15 @@ static bool CC_ARM_AAPCS_Custom_Aggregate(unsigned &ValNo, MVT &ValVT,
break;
}
+ case MVT::f16:
case MVT::f32:
RegList = SRegList;
break;
+ case MVT::v4f16:
case MVT::f64:
RegList = DRegList;
break;
+ case MVT::v8f16:
case MVT::v2f64:
RegList = QRegList;
break;
diff --git a/lib/Target/ARM/ARMCallingConv.td b/lib/Target/ARM/ARMCallingConv.td
index dcfd6518a840..f173e423f3e4 100644
--- a/lib/Target/ARM/ARMCallingConv.td
+++ b/lib/Target/ARM/ARMCallingConv.td
@@ -160,8 +160,8 @@ def CC_ARM_AAPCS : CallingConv<[
CCIfNest<CCAssignToReg<[R12]>>,
// Handle all vector types as either f64 or v2f64.
- CCIfType<[v1i64, v2i32, v4i16, v8i8, v2f32], CCBitConvertToType<f64>>,
- CCIfType<[v2i64, v4i32, v8i16, v16i8, v4f32], CCBitConvertToType<v2f64>>,
+ CCIfType<[v1i64, v2i32, v4i16, v4f16, v8i8, v2f32], CCBitConvertToType<f64>>,
+ CCIfType<[v2i64, v4i32, v8i16, v8f16, v16i8, v4f32], CCBitConvertToType<v2f64>>,
// Pass SwiftSelf in a callee saved register.
CCIfSwiftSelf<CCIfType<[i32], CCAssignToReg<[R10]>>>,
@@ -176,8 +176,8 @@ def CC_ARM_AAPCS : CallingConv<[
def RetCC_ARM_AAPCS : CallingConv<[
// Handle all vector types as either f64 or v2f64.
- CCIfType<[v1i64, v2i32, v4i16, v8i8, v2f32], CCBitConvertToType<f64>>,
- CCIfType<[v2i64, v4i32, v8i16, v16i8, v4f32], CCBitConvertToType<v2f64>>,
+ CCIfType<[v1i64, v2i32, v4i16, v4f16, v8i8, v2f32], CCBitConvertToType<f64>>,
+ CCIfType<[v2i64, v4i32, v8i16, v8f16,v16i8, v4f32], CCBitConvertToType<v2f64>>,
// Pass SwiftSelf in a callee saved register.
CCIfSwiftSelf<CCIfType<[i32], CCAssignToReg<[R10]>>>,
@@ -187,6 +187,7 @@ def RetCC_ARM_AAPCS : CallingConv<[
CCIfType<[f64, v2f64], CCCustom<"RetCC_ARM_AAPCS_Custom_f64">>,
CCIfType<[f32], CCBitConvertToType<i32>>,
+
CCDelegateTo<RetCC_ARM_AAPCS_Common>
]>;
@@ -200,8 +201,8 @@ def CC_ARM_AAPCS_VFP : CallingConv<[
CCIfByVal<CCPassByVal<4, 4>>,
// Handle all vector types as either f64 or v2f64.
- CCIfType<[v1i64, v2i32, v4i16, v8i8, v2f32], CCBitConvertToType<f64>>,
- CCIfType<[v2i64, v4i32, v8i16, v16i8, v4f32], CCBitConvertToType<v2f64>>,
+ CCIfType<[v1i64, v2i32, v4i16, v4f16, v8i8, v2f32], CCBitConvertToType<f64>>,
+ CCIfType<[v2i64, v4i32, v8i16, v8f16, v16i8, v4f32], CCBitConvertToType<v2f64>>,
// Pass SwiftSelf in a callee saved register.
CCIfSwiftSelf<CCIfType<[i32], CCAssignToReg<[R10]>>>,
@@ -221,8 +222,8 @@ def CC_ARM_AAPCS_VFP : CallingConv<[
def RetCC_ARM_AAPCS_VFP : CallingConv<[
// Handle all vector types as either f64 or v2f64.
- CCIfType<[v1i64, v2i32, v4i16, v8i8, v2f32], CCBitConvertToType<f64>>,
- CCIfType<[v2i64, v4i32, v8i16, v16i8, v4f32], CCBitConvertToType<v2f64>>,
+ CCIfType<[v1i64, v2i32, v4i16, v4f16, v8i8, v2f32], CCBitConvertToType<f64>>,
+ CCIfType<[v2i64, v4i32, v8i16, v8f16, v16i8, v4f32], CCBitConvertToType<v2f64>>,
// Pass SwiftSelf in a callee saved register.
CCIfSwiftSelf<CCIfType<[i32], CCAssignToReg<[R10]>>>,
@@ -233,7 +234,7 @@ def RetCC_ARM_AAPCS_VFP : CallingConv<[
CCIfType<[v2f64], CCAssignToReg<[Q0, Q1, Q2, Q3]>>,
CCIfType<[f64], CCAssignToReg<[D0, D1, D2, D3, D4, D5, D6, D7]>>,
CCIfType<[f32], CCAssignToReg<[S0, S1, S2, S3, S4, S5, S6, S7, S8,
- S9, S10, S11, S12, S13, S14, S15]>>,
+ S9, S10, S11, S12, S13, S14, S15]>>,
CCDelegateTo<RetCC_ARM_AAPCS_Common>
]>;
diff --git a/lib/Target/ARM/ARMCodeGenPrepare.cpp b/lib/Target/ARM/ARMCodeGenPrepare.cpp
new file mode 100644
index 000000000000..24071277427a
--- /dev/null
+++ b/lib/Target/ARM/ARMCodeGenPrepare.cpp
@@ -0,0 +1,750 @@
+//===----- ARMCodeGenPrepare.cpp ------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file
+/// This pass inserts intrinsics to handle small types that would otherwise be
+/// promoted during legalization. Here we can manually promote types or insert
+/// intrinsics which can handle narrow types that aren't supported by the
+/// register classes.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ARM.h"
+#include "ARMSubtarget.h"
+#include "ARMTargetMachine.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/CodeGen/Passes.h"
+#include "llvm/CodeGen/TargetPassConfig.h"
+#include "llvm/IR/Attributes.h"
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/InstrTypes.h"
+#include "llvm/IR/Instruction.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/Type.h"
+#include "llvm/IR/Value.h"
+#include "llvm/IR/Verifier.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/CommandLine.h"
+
+#define DEBUG_TYPE "arm-codegenprepare"
+
+using namespace llvm;
+
+static cl::opt<bool>
+DisableCGP("arm-disable-cgp", cl::Hidden, cl::init(true),
+ cl::desc("Disable ARM specific CodeGenPrepare pass"));
+
+static cl::opt<bool>
+EnableDSP("arm-enable-scalar-dsp", cl::Hidden, cl::init(false),
+ cl::desc("Use DSP instructions for scalar operations"));
+
+static cl::opt<bool>
+EnableDSPWithImms("arm-enable-scalar-dsp-imms", cl::Hidden, cl::init(false),
+ cl::desc("Use DSP instructions for scalar operations\
+ with immediate operands"));
+
+namespace {
+
+class IRPromoter {
+ SmallPtrSet<Value*, 8> NewInsts;
+ SmallVector<Instruction*, 4> InstsToRemove;
+ Module *M = nullptr;
+ LLVMContext &Ctx;
+
+public:
+ IRPromoter(Module *M) : M(M), Ctx(M->getContext()) { }
+
+ void Cleanup() {
+ for (auto *I : InstsToRemove) {
+ LLVM_DEBUG(dbgs() << "ARM CGP: Removing " << *I << "\n");
+ I->dropAllReferences();
+ I->eraseFromParent();
+ }
+ InstsToRemove.clear();
+ NewInsts.clear();
+ }
+
+ void Mutate(Type *OrigTy,
+ SmallPtrSetImpl<Value*> &Visited,
+ SmallPtrSetImpl<Value*> &Leaves,
+ SmallPtrSetImpl<Instruction*> &Roots);
+};
+
+class ARMCodeGenPrepare : public FunctionPass {
+ const ARMSubtarget *ST = nullptr;
+ IRPromoter *Promoter = nullptr;
+ std::set<Value*> AllVisited;
+ Type *OrigTy = nullptr;
+ unsigned TypeSize = 0;
+
+ bool isNarrowInstSupported(Instruction *I);
+ bool isSupportedValue(Value *V);
+ bool isLegalToPromote(Value *V);
+ bool TryToPromote(Value *V);
+
+public:
+ static char ID;
+
+ ARMCodeGenPrepare() : FunctionPass(ID) {}
+
+ void getAnalysisUsage(AnalysisUsage &AU) const override {
+ AU.addRequired<TargetPassConfig>();
+ }
+
+ StringRef getPassName() const override { return "ARM IR optimizations"; }
+
+ bool doInitialization(Module &M) override;
+ bool runOnFunction(Function &F) override;
+ bool doFinalization(Module &M) override;
+};
+
+}
+
+/// Can the given value generate sign bits.
+static bool isSigned(Value *V) {
+ if (!isa<Instruction>(V))
+ return false;
+
+ unsigned Opc = cast<Instruction>(V)->getOpcode();
+ return Opc == Instruction::AShr || Opc == Instruction::SDiv ||
+ Opc == Instruction::SRem;
+}
+
+/// Some instructions can use 8- and 16-bit operands, and we don't need to
+/// promote anything larger. We disallow booleans to make life easier when
+/// dealing with icmps but allow any other integer that is <= 16 bits. Void
+/// types are accepted so we can handle switches.
+static bool isSupportedType(Value *V) {
+ if (V->getType()->isVoidTy())
+ return true;
+
+ const IntegerType *IntTy = dyn_cast<IntegerType>(V->getType());
+ if (!IntTy)
+ return false;
+
+ // Don't try to promote boolean values.
+ if (IntTy->getBitWidth() == 1)
+ return false;
+
+ if (auto *ZExt = dyn_cast<ZExtInst>(V))
+ return isSupportedType(ZExt->getOperand(0));
+
+ return IntTy->getBitWidth() <= 16;
+}
+
+/// Return true if V will require any promoted values to be truncated for the
+/// use to be valid.
+static bool isSink(Value *V) {
+ auto UsesNarrowValue = [](Value *V) {
+ return V->getType()->getScalarSizeInBits() <= 32;
+ };
+
+ if (auto *Store = dyn_cast<StoreInst>(V))
+ return UsesNarrowValue(Store->getValueOperand());
+ if (auto *Return = dyn_cast<ReturnInst>(V))
+ return UsesNarrowValue(Return->getReturnValue());
+
+ return isa<CallInst>(V);
+}
+
+/// Return true if the given value is a leaf that will need to be zext'd.
+static bool isSource(Value *V) {
+ if (isa<Argument>(V) && isSupportedType(V))
+ return true;
+ else if (isa<TruncInst>(V))
+ return true;
+ else if (auto *ZExt = dyn_cast<ZExtInst>(V))
+ // ZExt can be a leaf if its the only user of a load.
+ return isa<LoadInst>(ZExt->getOperand(0)) &&
+ ZExt->getOperand(0)->hasOneUse();
+ else if (auto *Call = dyn_cast<CallInst>(V))
+ return Call->hasRetAttr(Attribute::AttrKind::ZExt);
+ else if (auto *Load = dyn_cast<LoadInst>(V)) {
+ if (!isa<IntegerType>(Load->getType()))
+ return false;
+ // A load is a leaf, unless its already just being zext'd.
+ if (Load->hasOneUse() && isa<ZExtInst>(*Load->use_begin()))
+ return false;
+
+ return true;
+ }
+ return false;
+}
+
+/// Return whether the instruction can be promoted within any modifications to
+/// it's operands or result.
+static bool isSafeOverflow(Instruction *I) {
+ if (isa<OverflowingBinaryOperator>(I) && I->hasNoUnsignedWrap())
+ return true;
+
+ unsigned Opc = I->getOpcode();
+ if (Opc == Instruction::Add || Opc == Instruction::Sub) {
+ // We don't care if the add or sub could wrap if the value is decreasing
+ // and is only being used by an unsigned compare.
+ if (!I->hasOneUse() ||
+ !isa<ICmpInst>(*I->user_begin()) ||
+ !isa<ConstantInt>(I->getOperand(1)))
+ return false;
+
+ auto *CI = cast<ICmpInst>(*I->user_begin());
+ if (CI->isSigned())
+ return false;
+
+ bool NegImm = cast<ConstantInt>(I->getOperand(1))->isNegative();
+ bool IsDecreasing = ((Opc == Instruction::Sub) && !NegImm) ||
+ ((Opc == Instruction::Add) && NegImm);
+ if (!IsDecreasing)
+ return false;
+
+ LLVM_DEBUG(dbgs() << "ARM CGP: Allowing safe overflow for " << *I << "\n");
+ return true;
+ }
+
+ // Otherwise, if an instruction is using a negative immediate we will need
+ // to fix it up during the promotion.
+ for (auto &Op : I->operands()) {
+ if (auto *Const = dyn_cast<ConstantInt>(Op))
+ if (Const->isNegative())
+ return false;
+ }
+ return false;
+}
+
+static bool shouldPromote(Value *V) {
+ auto *I = dyn_cast<Instruction>(V);
+ if (!I)
+ return false;
+
+ if (!isa<IntegerType>(V->getType()))
+ return false;
+
+ if (isa<StoreInst>(I) || isa<TerminatorInst>(I) || isa<TruncInst>(I) ||
+ isa<ICmpInst>(I))
+ return false;
+
+ if (auto *ZExt = dyn_cast<ZExtInst>(I))
+ return !ZExt->getDestTy()->isIntegerTy(32);
+
+ return true;
+}
+
+/// Return whether we can safely mutate V's type to ExtTy without having to be
+/// concerned with zero extending or truncation.
+static bool isPromotedResultSafe(Value *V) {
+ if (!isa<Instruction>(V))
+ return true;
+
+ if (isSigned(V))
+ return false;
+
+ // If I is only being used by something that will require its value to be
+ // truncated, then we don't care about the promoted result.
+ auto *I = cast<Instruction>(V);
+ if (I->hasOneUse() && isSink(*I->use_begin()))
+ return true;
+
+ if (isa<OverflowingBinaryOperator>(I))
+ return isSafeOverflow(I);
+ return true;
+}
+
+/// Return the intrinsic for the instruction that can perform the same
+/// operation but on a narrow type. This is using the parallel dsp intrinsics
+/// on scalar values.
+static Intrinsic::ID getNarrowIntrinsic(Instruction *I, unsigned TypeSize) {
+ // Whether we use the signed or unsigned versions of these intrinsics
+ // doesn't matter because we're not using the GE bits that they set in
+ // the APSR.
+ switch(I->getOpcode()) {
+ default:
+ break;
+ case Instruction::Add:
+ return TypeSize == 16 ? Intrinsic::arm_uadd16 :
+ Intrinsic::arm_uadd8;
+ case Instruction::Sub:
+ return TypeSize == 16 ? Intrinsic::arm_usub16 :
+ Intrinsic::arm_usub8;
+ }
+ llvm_unreachable("unhandled opcode for narrow intrinsic");
+}
+
+void IRPromoter::Mutate(Type *OrigTy,
+ SmallPtrSetImpl<Value*> &Visited,
+ SmallPtrSetImpl<Value*> &Leaves,
+ SmallPtrSetImpl<Instruction*> &Roots) {
+ IRBuilder<> Builder{Ctx};
+ Type *ExtTy = Type::getInt32Ty(M->getContext());
+ unsigned TypeSize = OrigTy->getPrimitiveSizeInBits();
+ SmallPtrSet<Value*, 8> Promoted;
+ LLVM_DEBUG(dbgs() << "ARM CGP: Promoting use-def chains to from " << TypeSize
+ << " to 32-bits\n");
+
+ auto ReplaceAllUsersOfWith = [&](Value *From, Value *To) {
+ SmallVector<Instruction*, 4> Users;
+ Instruction *InstTo = dyn_cast<Instruction>(To);
+ for (Use &U : From->uses()) {
+ auto *User = cast<Instruction>(U.getUser());
+ if (InstTo && User->isIdenticalTo(InstTo))
+ continue;
+ Users.push_back(User);
+ }
+
+ for (auto &U : Users)
+ U->replaceUsesOfWith(From, To);
+ };
+
+ auto FixConst = [&](ConstantInt *Const, Instruction *I) {
+ Constant *NewConst = nullptr;
+ if (isSafeOverflow(I)) {
+ NewConst = (Const->isNegative()) ?
+ ConstantExpr::getSExt(Const, ExtTy) :
+ ConstantExpr::getZExt(Const, ExtTy);
+ } else {
+ uint64_t NewVal = *Const->getValue().getRawData();
+ if (Const->getType() == Type::getInt16Ty(Ctx))
+ NewVal &= 0xFFFF;
+ else
+ NewVal &= 0xFF;
+ NewConst = ConstantInt::get(ExtTy, NewVal);
+ }
+ I->replaceUsesOfWith(Const, NewConst);
+ };
+
+ auto InsertDSPIntrinsic = [&](Instruction *I) {
+ LLVM_DEBUG(dbgs() << "ARM CGP: Inserting DSP intrinsic for "
+ << *I << "\n");
+ Function *DSPInst =
+ Intrinsic::getDeclaration(M, getNarrowIntrinsic(I, TypeSize));
+ Builder.SetInsertPoint(I);
+ Builder.SetCurrentDebugLocation(I->getDebugLoc());
+ Value *Args[] = { I->getOperand(0), I->getOperand(1) };
+ CallInst *Call = Builder.CreateCall(DSPInst, Args);
+ ReplaceAllUsersOfWith(I, Call);
+ InstsToRemove.push_back(I);
+ NewInsts.insert(Call);
+ };
+
+ auto InsertZExt = [&](Value *V, Instruction *InsertPt) {
+ LLVM_DEBUG(dbgs() << "ARM CGP: Inserting ZExt for " << *V << "\n");
+ Builder.SetInsertPoint(InsertPt);
+ if (auto *I = dyn_cast<Instruction>(V))
+ Builder.SetCurrentDebugLocation(I->getDebugLoc());
+ auto *ZExt = cast<Instruction>(Builder.CreateZExt(V, ExtTy));
+ if (isa<Argument>(V))
+ ZExt->moveBefore(InsertPt);
+ else
+ ZExt->moveAfter(InsertPt);
+ ReplaceAllUsersOfWith(V, ZExt);
+ NewInsts.insert(ZExt);
+ };
+
+ // First, insert extending instructions between the leaves and their users.
+ LLVM_DEBUG(dbgs() << "ARM CGP: Promoting leaves:\n");
+ for (auto V : Leaves) {
+ LLVM_DEBUG(dbgs() << " - " << *V << "\n");
+ if (auto *ZExt = dyn_cast<ZExtInst>(V))
+ ZExt->mutateType(ExtTy);
+ else if (auto *I = dyn_cast<Instruction>(V))
+ InsertZExt(I, I);
+ else if (auto *Arg = dyn_cast<Argument>(V)) {
+ BasicBlock &BB = Arg->getParent()->front();
+ InsertZExt(Arg, &*BB.getFirstInsertionPt());
+ } else {
+ llvm_unreachable("unhandled leaf that needs extending");
+ }
+ Promoted.insert(V);
+ }
+
+ LLVM_DEBUG(dbgs() << "ARM CGP: Mutating the tree..\n");
+ // Then mutate the types of the instructions within the tree. Here we handle
+ // constant operands.
+ for (auto *V : Visited) {
+ if (Leaves.count(V))
+ continue;
+
+ if (!isa<Instruction>(V))
+ continue;
+
+ auto *I = cast<Instruction>(V);
+ if (Roots.count(I))
+ continue;
+
+ for (auto &U : I->operands()) {
+ if ((U->getType() == ExtTy) || !isSupportedType(&*U))
+ continue;
+
+ if (auto *Const = dyn_cast<ConstantInt>(&*U))
+ FixConst(Const, I);
+ else if (isa<UndefValue>(&*U))
+ U->mutateType(ExtTy);
+ }
+
+ if (shouldPromote(I)) {
+ I->mutateType(ExtTy);
+ Promoted.insert(I);
+ }
+ }
+
+ // Now we need to remove any zexts that have become unnecessary, as well
+ // as insert any intrinsics.
+ for (auto *V : Visited) {
+ if (Leaves.count(V))
+ continue;
+ if (auto *ZExt = dyn_cast<ZExtInst>(V)) {
+ if (ZExt->getDestTy() != ExtTy) {
+ ZExt->mutateType(ExtTy);
+ Promoted.insert(ZExt);
+ }
+ else if (ZExt->getSrcTy() == ExtTy) {
+ ReplaceAllUsersOfWith(V, ZExt->getOperand(0));
+ InstsToRemove.push_back(ZExt);
+ }
+ continue;
+ }
+
+ if (!shouldPromote(V) || isPromotedResultSafe(V))
+ continue;
+
+ // Replace unsafe instructions with appropriate intrinsic calls.
+ InsertDSPIntrinsic(cast<Instruction>(V));
+ }
+
+ LLVM_DEBUG(dbgs() << "ARM CGP: Fixing up the roots:\n");
+ // Fix up any stores or returns that use the results of the promoted
+ // chain.
+ for (auto I : Roots) {
+ LLVM_DEBUG(dbgs() << " - " << *I << "\n");
+ Type *TruncTy = OrigTy;
+ if (auto *Store = dyn_cast<StoreInst>(I)) {
+ auto *PtrTy = cast<PointerType>(Store->getPointerOperandType());
+ TruncTy = PtrTy->getElementType();
+ } else if (isa<ReturnInst>(I)) {
+ Function *F = I->getParent()->getParent();
+ TruncTy = F->getFunctionType()->getReturnType();
+ }
+
+ for (unsigned i = 0; i < I->getNumOperands(); ++i) {
+ Value *V = I->getOperand(i);
+ if (Promoted.count(V) || NewInsts.count(V)) {
+ if (auto *Op = dyn_cast<Instruction>(V)) {
+
+ if (auto *Call = dyn_cast<CallInst>(I))
+ TruncTy = Call->getFunctionType()->getParamType(i);
+
+ if (TruncTy == ExtTy)
+ continue;
+
+ LLVM_DEBUG(dbgs() << "ARM CGP: Creating " << *TruncTy
+ << " Trunc for " << *Op << "\n");
+ Builder.SetInsertPoint(Op);
+ auto *Trunc = cast<Instruction>(Builder.CreateTrunc(Op, TruncTy));
+ Trunc->moveBefore(I);
+ I->setOperand(i, Trunc);
+ NewInsts.insert(Trunc);
+ }
+ }
+ }
+ }
+ LLVM_DEBUG(dbgs() << "ARM CGP: Mutation complete.\n");
+}
+
+bool ARMCodeGenPrepare::isNarrowInstSupported(Instruction *I) {
+ if (!ST->hasDSP() || !EnableDSP || !isSupportedType(I))
+ return false;
+
+ if (ST->isThumb() && !ST->hasThumb2())
+ return false;
+
+ if (I->getOpcode() != Instruction::Add && I->getOpcode() != Instruction::Sub)
+ return false;
+
+ // TODO
+ // Would it be profitable? For Thumb code, these parallel DSP instructions
+ // are only Thumb-2, so we wouldn't be able to dual issue on Cortex-M33. For
+ // Cortex-A, specifically Cortex-A72, the latency is double and throughput is
+ // halved. They also do not take immediates as operands.
+ for (auto &Op : I->operands()) {
+ if (isa<Constant>(Op)) {
+ if (!EnableDSPWithImms)
+ return false;
+ }
+ }
+ return true;
+}
+
+/// We accept most instructions, as well as Arguments and ConstantInsts. We
+/// Disallow casts other than zext and truncs and only allow calls if their
+/// return value is zeroext. We don't allow opcodes that can introduce sign
+/// bits.
+bool ARMCodeGenPrepare::isSupportedValue(Value *V) {
+ LLVM_DEBUG(dbgs() << "ARM CGP: Is " << *V << " supported?\n");
+
+ // Non-instruction values that we can handle.
+ if (isa<ConstantInt>(V) || isa<Argument>(V))
+ return true;
+
+ // Memory instructions
+ if (isa<StoreInst>(V) || isa<LoadInst>(V) || isa<GetElementPtrInst>(V))
+ return true;
+
+ // Branches and targets.
+ if (auto *ICmp = dyn_cast<ICmpInst>(V))
+ return ICmp->isEquality() || !ICmp->isSigned();
+
+ if( isa<BranchInst>(V) || isa<SwitchInst>(V) || isa<BasicBlock>(V))
+ return true;
+
+ if (isa<PHINode>(V) || isa<SelectInst>(V) || isa<ReturnInst>(V))
+ return true;
+
+ // Special cases for calls as we need to check for zeroext
+ // TODO We should accept calls even if they don't have zeroext, as they can
+ // still be roots.
+ if (auto *Call = dyn_cast<CallInst>(V))
+ return Call->hasRetAttr(Attribute::AttrKind::ZExt);
+ else if (auto *Cast = dyn_cast<CastInst>(V)) {
+ if (isa<ZExtInst>(Cast))
+ return Cast->getDestTy()->getScalarSizeInBits() <= 32;
+ else if (auto *Trunc = dyn_cast<TruncInst>(V))
+ return Trunc->getDestTy()->getScalarSizeInBits() <= TypeSize;
+ else {
+ LLVM_DEBUG(dbgs() << "ARM CGP: No, unsupported cast.\n");
+ return false;
+ }
+ } else if (!isa<BinaryOperator>(V)) {
+ LLVM_DEBUG(dbgs() << "ARM CGP: No, not a binary operator.\n");
+ return false;
+ }
+
+ bool res = !isSigned(V);
+ if (!res)
+ LLVM_DEBUG(dbgs() << "ARM CGP: No, it's a signed instruction.\n");
+ return res;
+}
+
+/// Check that the type of V would be promoted and that the original type is
+/// smaller than the targeted promoted type. Check that we're not trying to
+/// promote something larger than our base 'TypeSize' type.
+bool ARMCodeGenPrepare::isLegalToPromote(Value *V) {
+ if (!isSupportedType(V))
+ return false;
+
+ unsigned VSize = 0;
+ if (auto *Ld = dyn_cast<LoadInst>(V)) {
+ auto *PtrTy = cast<PointerType>(Ld->getPointerOperandType());
+ VSize = PtrTy->getElementType()->getPrimitiveSizeInBits();
+ } else if (auto *ZExt = dyn_cast<ZExtInst>(V)) {
+ VSize = ZExt->getOperand(0)->getType()->getPrimitiveSizeInBits();
+ } else {
+ VSize = V->getType()->getPrimitiveSizeInBits();
+ }
+
+ if (VSize > TypeSize)
+ return false;
+
+ if (isPromotedResultSafe(V))
+ return true;
+
+ if (auto *I = dyn_cast<Instruction>(V))
+ return isNarrowInstSupported(I);
+
+ return false;
+}
+
+bool ARMCodeGenPrepare::TryToPromote(Value *V) {
+ OrigTy = V->getType();
+ TypeSize = OrigTy->getPrimitiveSizeInBits();
+
+ if (!isSupportedValue(V) || !shouldPromote(V) || !isLegalToPromote(V))
+ return false;
+
+ LLVM_DEBUG(dbgs() << "ARM CGP: TryToPromote: " << *V << "\n");
+
+ SetVector<Value*> WorkList;
+ SmallPtrSet<Value*, 8> Leaves;
+ SmallPtrSet<Instruction*, 4> Roots;
+ WorkList.insert(V);
+ SmallPtrSet<Value*, 16> CurrentVisited;
+ CurrentVisited.clear();
+
+ // Return true if the given value can, or has been, visited. Add V to the
+ // worklist if needed.
+ auto AddLegalInst = [&](Value *V) {
+ if (CurrentVisited.count(V))
+ return true;
+
+ if (!isSupportedValue(V) || (shouldPromote(V) && !isLegalToPromote(V))) {
+ LLVM_DEBUG(dbgs() << "ARM CGP: Can't handle: " << *V << "\n");
+ return false;
+ }
+
+ WorkList.insert(V);
+ return true;
+ };
+
+ // Iterate through, and add to, a tree of operands and users in the use-def.
+ while (!WorkList.empty()) {
+ Value *V = WorkList.back();
+ WorkList.pop_back();
+ if (CurrentVisited.count(V))
+ continue;
+
+ if (!isa<Instruction>(V) && !isSource(V))
+ continue;
+
+ // If we've already visited this value from somewhere, bail now because
+ // the tree has already been explored.
+ // TODO: This could limit the transform, ie if we try to promote something
+ // from an i8 and fail first, before trying an i16.
+ if (AllVisited.count(V)) {
+ LLVM_DEBUG(dbgs() << "ARM CGP: Already visited this: " << *V << "\n");
+ return false;
+ }
+
+ CurrentVisited.insert(V);
+ AllVisited.insert(V);
+
+ // Calls can be both sources and sinks.
+ if (isSink(V))
+ Roots.insert(cast<Instruction>(V));
+ if (isSource(V))
+ Leaves.insert(V);
+ else if (auto *I = dyn_cast<Instruction>(V)) {
+ // Visit operands of any instruction visited.
+ for (auto &U : I->operands()) {
+ if (!AddLegalInst(U))
+ return false;
+ }
+ }
+
+ // Don't visit users of a node which isn't going to be mutated unless its a
+ // source.
+ if (isSource(V) || shouldPromote(V)) {
+ for (Use &U : V->uses()) {
+ if (!AddLegalInst(U.getUser()))
+ return false;
+ }
+ }
+ }
+
+ unsigned NumToPromote = 0;
+ unsigned Cost = 0;
+ for (auto *V : CurrentVisited) {
+ // Truncs will cause a uxt and no zeroext arguments will often require
+ // a uxt somewhere.
+ if (isa<TruncInst>(V))
+ ++Cost;
+ else if (auto *Arg = dyn_cast<Argument>(V)) {
+ if (!Arg->hasZExtAttr())
+ ++Cost;
+ }
+
+ // Mem ops can automatically be extended/truncated and non-instructions
+ // don't need anything done.
+ if (Leaves.count(V) || isa<StoreInst>(V) || !isa<Instruction>(V))
+ continue;
+
+ // Will need to truncate calls args and returns.
+ if (Roots.count(cast<Instruction>(V))) {
+ ++Cost;
+ continue;
+ }
+
+ if (shouldPromote(V))
+ ++NumToPromote;
+ }
+
+ LLVM_DEBUG(dbgs() << "ARM CGP: Visited nodes:\n";
+ for (auto *I : CurrentVisited)
+ I->dump();
+ );
+ LLVM_DEBUG(dbgs() << "ARM CGP: Cost of promoting " << NumToPromote
+ << " instructions = " << Cost << "\n");
+ if (Cost > NumToPromote || (NumToPromote == 0))
+ return false;
+
+ Promoter->Mutate(OrigTy, CurrentVisited, Leaves, Roots);
+ return true;
+}
+
+bool ARMCodeGenPrepare::doInitialization(Module &M) {
+ Promoter = new IRPromoter(&M);
+ return false;
+}
+
+bool ARMCodeGenPrepare::runOnFunction(Function &F) {
+ if (skipFunction(F) || DisableCGP)
+ return false;
+
+ auto *TPC = &getAnalysis<TargetPassConfig>();
+ if (!TPC)
+ return false;
+
+ const TargetMachine &TM = TPC->getTM<TargetMachine>();
+ ST = &TM.getSubtarget<ARMSubtarget>(F);
+ bool MadeChange = false;
+ LLVM_DEBUG(dbgs() << "ARM CGP: Running on " << F.getName() << "\n");
+
+ // Search up from icmps to try to promote their operands.
+ for (BasicBlock &BB : F) {
+ auto &Insts = BB.getInstList();
+ for (auto &I : Insts) {
+ if (AllVisited.count(&I))
+ continue;
+
+ if (isa<ICmpInst>(I)) {
+ auto &CI = cast<ICmpInst>(I);
+
+ // Skip signed or pointer compares
+ if (CI.isSigned() || !isa<IntegerType>(CI.getOperand(0)->getType()))
+ continue;
+
+ LLVM_DEBUG(dbgs() << "ARM CGP: Searching from: " << CI << "\n");
+ for (auto &Op : CI.operands()) {
+ if (auto *I = dyn_cast<Instruction>(Op)) {
+ if (isa<ZExtInst>(I))
+ MadeChange |= TryToPromote(I->getOperand(0));
+ else
+ MadeChange |= TryToPromote(I);
+ }
+ }
+ }
+ }
+ Promoter->Cleanup();
+ LLVM_DEBUG(if (verifyFunction(F, &dbgs())) {
+ dbgs();
+ report_fatal_error("Broken function after type promotion");
+ });
+ }
+ if (MadeChange)
+ LLVM_DEBUG(dbgs() << "After ARMCodeGenPrepare: " << F << "\n");
+
+ return MadeChange;
+}
+
+bool ARMCodeGenPrepare::doFinalization(Module &M) {
+ delete Promoter;
+ return false;
+}
+
+INITIALIZE_PASS_BEGIN(ARMCodeGenPrepare, DEBUG_TYPE,
+ "ARM IR optimizations", false, false)
+INITIALIZE_PASS_END(ARMCodeGenPrepare, DEBUG_TYPE, "ARM IR optimizations",
+ false, false)
+
+char ARMCodeGenPrepare::ID = 0;
+
+FunctionPass *llvm::createARMCodeGenPreparePass() {
+ return new ARMCodeGenPrepare();
+}
diff --git a/lib/Target/ARM/ARMComputeBlockSize.cpp b/lib/Target/ARM/ARMComputeBlockSize.cpp
index 2e97b99b05a7..b263e9d86c42 100644
--- a/lib/Target/ARM/ARMComputeBlockSize.cpp
+++ b/lib/Target/ARM/ARMComputeBlockSize.cpp
@@ -35,6 +35,7 @@ mayOptimizeThumb2Instruction(const MachineInstr *MI) {
case ARM::tBcc:
// optimizeThumb2JumpTables.
case ARM::t2BR_JT:
+ case ARM::tBR_JTr:
return true;
}
return false;
diff --git a/lib/Target/ARM/ARMConstantIslandPass.cpp b/lib/Target/ARM/ARMConstantIslandPass.cpp
index 8baee1ce281d..de08eb8c6985 100644
--- a/lib/Target/ARM/ARMConstantIslandPass.cpp
+++ b/lib/Target/ARM/ARMConstantIslandPass.cpp
@@ -35,6 +35,7 @@
#include "llvm/CodeGen/MachineJumpTableInfo.h"
#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/Config/llvm-config.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DebugLoc.h"
#include "llvm/MC/MCInstrDesc.h"
@@ -301,7 +302,7 @@ void ARMConstantIslands::verify() {
return BBInfo[LHS.getNumber()].postOffset() <
BBInfo[RHS.getNumber()].postOffset();
}));
- DEBUG(dbgs() << "Verifying " << CPUsers.size() << " CP users.\n");
+ LLVM_DEBUG(dbgs() << "Verifying " << CPUsers.size() << " CP users.\n");
for (unsigned i = 0, e = CPUsers.size(); i != e; ++i) {
CPUser &U = CPUsers[i];
unsigned UserOffset = getUserOffset(U);
@@ -309,12 +310,12 @@ void ARMConstantIslands::verify() {
// adjustment.
if (isCPEntryInRange(U.MI, UserOffset, U.CPEMI, U.getMaxDisp()+2, U.NegOk,
/* DoDump = */ true)) {
- DEBUG(dbgs() << "OK\n");
+ LLVM_DEBUG(dbgs() << "OK\n");
continue;
}
- DEBUG(dbgs() << "Out of range.\n");
+ LLVM_DEBUG(dbgs() << "Out of range.\n");
dumpBBs();
- DEBUG(MF->dump());
+ LLVM_DEBUG(MF->dump());
llvm_unreachable("Constant pool entry out of range!");
}
#endif
@@ -323,7 +324,7 @@ void ARMConstantIslands::verify() {
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
/// print block size and offset information - debugging
LLVM_DUMP_METHOD void ARMConstantIslands::dumpBBs() {
- DEBUG({
+ LLVM_DEBUG({
for (unsigned J = 0, E = BBInfo.size(); J !=E; ++J) {
const BasicBlockInfo &BBI = BBInfo[J];
dbgs() << format("%08x %bb.%u\t", BBI.Offset, J)
@@ -340,9 +341,9 @@ bool ARMConstantIslands::runOnMachineFunction(MachineFunction &mf) {
MF = &mf;
MCP = mf.getConstantPool();
- DEBUG(dbgs() << "***** ARMConstantIslands: "
- << MCP->getConstants().size() << " CP entries, aligned to "
- << MCP->getConstantPoolAlignment() << " bytes *****\n");
+ LLVM_DEBUG(dbgs() << "***** ARMConstantIslands: "
+ << MCP->getConstants().size() << " CP entries, aligned to "
+ << MCP->getConstantPoolAlignment() << " bytes *****\n");
STI = &static_cast<const ARMSubtarget &>(MF->getSubtarget());
TII = STI->getInstrInfo();
@@ -393,7 +394,7 @@ bool ARMConstantIslands::runOnMachineFunction(MachineFunction &mf) {
// constant pool users.
initializeFunctionInfo(CPEMIs);
CPEMIs.clear();
- DEBUG(dumpBBs());
+ LLVM_DEBUG(dumpBBs());
// Functions with jump tables need an alignment of 4 because they use the ADR
// instruction, which aligns the PC to 4 bytes before adding an offset.
@@ -407,7 +408,7 @@ bool ARMConstantIslands::runOnMachineFunction(MachineFunction &mf) {
// is no change.
unsigned NoCPIters = 0, NoBRIters = 0;
while (true) {
- DEBUG(dbgs() << "Beginning CP iteration #" << NoCPIters << '\n');
+ LLVM_DEBUG(dbgs() << "Beginning CP iteration #" << NoCPIters << '\n');
bool CPChange = false;
for (unsigned i = 0, e = CPUsers.size(); i != e; ++i)
// For most inputs, it converges in no more than 5 iterations.
@@ -416,19 +417,19 @@ bool ARMConstantIslands::runOnMachineFunction(MachineFunction &mf) {
CPChange |= handleConstantPoolUser(i, NoCPIters >= CPMaxIteration / 2);
if (CPChange && ++NoCPIters > CPMaxIteration)
report_fatal_error("Constant Island pass failed to converge!");
- DEBUG(dumpBBs());
+ LLVM_DEBUG(dumpBBs());
// Clear NewWaterList now. If we split a block for branches, it should
// appear as "new water" for the next iteration of constant pool placement.
NewWaterList.clear();
- DEBUG(dbgs() << "Beginning BR iteration #" << NoBRIters << '\n');
+ LLVM_DEBUG(dbgs() << "Beginning BR iteration #" << NoBRIters << '\n');
bool BRChange = false;
for (unsigned i = 0, e = ImmBranches.size(); i != e; ++i)
BRChange |= fixupImmediateBr(ImmBranches[i]);
if (BRChange && ++NoBRIters > 30)
report_fatal_error("Branch Fix Up pass failed to converge!");
- DEBUG(dumpBBs());
+ LLVM_DEBUG(dumpBBs());
if (!CPChange && !BRChange)
break;
@@ -464,7 +465,7 @@ bool ARMConstantIslands::runOnMachineFunction(MachineFunction &mf) {
}
}
- DEBUG(dbgs() << '\n'; dumpBBs());
+ LLVM_DEBUG(dbgs() << '\n'; dumpBBs());
BBInfo.clear();
WaterList.clear();
@@ -479,7 +480,7 @@ bool ARMConstantIslands::runOnMachineFunction(MachineFunction &mf) {
return MadeChange;
}
-/// \brief Perform the initial placement of the regular constant pool entries.
+/// Perform the initial placement of the regular constant pool entries.
/// To start with, we put them all at the end of the function.
void
ARMConstantIslands::doInitialConstPlacement(std::vector<MachineInstr*> &CPEMIs) {
@@ -510,7 +511,6 @@ ARMConstantIslands::doInitialConstPlacement(std::vector<MachineInstr*> &CPEMIs)
const DataLayout &TD = MF->getDataLayout();
for (unsigned i = 0, e = CPs.size(); i != e; ++i) {
unsigned Size = TD.getTypeAllocSize(CPs[i].getType());
- assert(Size >= 4 && "Too small constant pool entry");
unsigned Align = CPs[i].getAlignment();
assert(isPowerOf2_32(Align) && "Invalid alignment");
// Verify that all constant pool entries are a multiple of their alignment.
@@ -534,13 +534,13 @@ ARMConstantIslands::doInitialConstPlacement(std::vector<MachineInstr*> &CPEMIs)
// Add a new CPEntry, but no corresponding CPUser yet.
CPEntries.emplace_back(1, CPEntry(CPEMI, i));
++NumCPEs;
- DEBUG(dbgs() << "Moved CPI#" << i << " to end of function, size = "
- << Size << ", align = " << Align <<'\n');
+ LLVM_DEBUG(dbgs() << "Moved CPI#" << i << " to end of function, size = "
+ << Size << ", align = " << Align << '\n');
}
- DEBUG(BB->dump());
+ LLVM_DEBUG(BB->dump());
}
-/// \brief Do initial placement of the jump tables. Because Thumb2's TBB and TBH
+/// Do initial placement of the jump tables. Because Thumb2's TBB and TBH
/// instructions can be made more efficient if the jump table immediately
/// follows the instruction, it's best to place them immediately next to their
/// jumps to begin with. In almost all cases they'll never be moved from that
@@ -701,7 +701,7 @@ initializeFunctionInfo(const std::vector<MachineInstr*> &CPEMIs) {
WaterList.push_back(&MBB);
for (MachineInstr &I : MBB) {
- if (I.isDebugValue())
+ if (I.isDebugInstr())
continue;
unsigned Opc = I.getOpcode();
@@ -820,6 +820,11 @@ initializeFunctionInfo(const std::vector<MachineInstr*> &CPEMIs) {
Scale = 4; // +-(offset_8*4)
NegOk = true;
break;
+ case ARM::VLDRH:
+ Bits = 8;
+ Scale = 2; // +-(offset_8*2)
+ NegOk = true;
+ break;
case ARM::tLDRHi:
Bits = 5;
@@ -1066,7 +1071,7 @@ bool ARMConstantIslands::isCPEntryInRange(MachineInstr *MI, unsigned UserOffset,
unsigned CPEOffset = getOffsetOf(CPEMI);
if (DoDump) {
- DEBUG({
+ LLVM_DEBUG({
unsigned Block = MI->getParent()->getNumber();
const BasicBlockInfo &BBI = BBInfo[Block];
dbgs() << "User of CPE#" << CPEMI->getOperand(0).getImm()
@@ -1159,7 +1164,7 @@ int ARMConstantIslands::findInRangeCPEntry(CPUser& U, unsigned UserOffset) {
// Check to see if the CPE is already in-range.
if (isCPEntryInRange(UserMI, UserOffset, CPEMI, U.getMaxDisp(), U.NegOk,
true)) {
- DEBUG(dbgs() << "In range\n");
+ LLVM_DEBUG(dbgs() << "In range\n");
return 1;
}
@@ -1175,8 +1180,8 @@ int ARMConstantIslands::findInRangeCPEntry(CPUser& U, unsigned UserOffset) {
continue;
if (isCPEntryInRange(UserMI, UserOffset, CPEs[i].CPEMI, U.getMaxDisp(),
U.NegOk)) {
- DEBUG(dbgs() << "Replacing CPE#" << CPI << " with CPE#"
- << CPEs[i].CPI << "\n");
+ LLVM_DEBUG(dbgs() << "Replacing CPE#" << CPI << " with CPE#"
+ << CPEs[i].CPI << "\n");
// Point the CPUser node to the replacement
U.CPEMI = CPEs[i].CPEMI;
// Change the CPI in the instruction operand to refer to the clone.
@@ -1261,8 +1266,8 @@ bool ARMConstantIslands::findAvailableWater(CPUser &U, unsigned UserOffset,
// This is the least amount of required padding seen so far.
BestGrowth = Growth;
WaterIter = IP;
- DEBUG(dbgs() << "Found water after " << printMBBReference(*WaterBB)
- << " Growth=" << Growth << '\n');
+ LLVM_DEBUG(dbgs() << "Found water after " << printMBBReference(*WaterBB)
+ << " Growth=" << Growth << '\n');
if (CloserWater && WaterBB == U.MI->getParent())
return true;
@@ -1305,8 +1310,8 @@ void ARMConstantIslands::createNewWater(unsigned CPUserIndex,
unsigned CPEOffset = UserBBI.postOffset(CPELogAlign) + Delta;
if (isOffsetInRange(UserOffset, CPEOffset, U)) {
- DEBUG(dbgs() << "Split at end of " << printMBBReference(*UserMBB)
- << format(", expected CPE offset %#x\n", CPEOffset));
+ LLVM_DEBUG(dbgs() << "Split at end of " << printMBBReference(*UserMBB)
+ << format(", expected CPE offset %#x\n", CPEOffset));
NewMBB = &*++UserMBB->getIterator();
// Add an unconditional branch from UserMBB to fallthrough block. Record
// it for branch lengthening; this new branch will not get out of range,
@@ -1349,18 +1354,17 @@ void ARMConstantIslands::createNewWater(unsigned CPUserIndex,
unsigned KnownBits = UserBBI.internalKnownBits();
unsigned UPad = UnknownPadding(LogAlign, KnownBits);
unsigned BaseInsertOffset = UserOffset + U.getMaxDisp() - UPad;
- DEBUG(dbgs() << format("Split in middle of big block before %#x",
- BaseInsertOffset));
+ LLVM_DEBUG(dbgs() << format("Split in middle of big block before %#x",
+ BaseInsertOffset));
// The 4 in the following is for the unconditional branch we'll be inserting
// (allows for long branch on Thumb1). Alignment of the island is handled
// inside isOffsetInRange.
BaseInsertOffset -= 4;
- DEBUG(dbgs() << format(", adjusted to %#x", BaseInsertOffset)
- << " la=" << LogAlign
- << " kb=" << KnownBits
- << " up=" << UPad << '\n');
+ LLVM_DEBUG(dbgs() << format(", adjusted to %#x", BaseInsertOffset)
+ << " la=" << LogAlign << " kb=" << KnownBits
+ << " up=" << UPad << '\n');
// This could point off the end of the block if we've already got constant
// pool entries following this block; only the last one is in the water list.
@@ -1373,7 +1377,7 @@ void ARMConstantIslands::createNewWater(unsigned CPUserIndex,
BaseInsertOffset =
std::max(UserBBI.postOffset() - UPad - 8,
UserOffset + TII->getInstSizeInBytes(*UserMI) + 1);
- DEBUG(dbgs() << format("Move inside block: %#x\n", BaseInsertOffset));
+ LLVM_DEBUG(dbgs() << format("Move inside block: %#x\n", BaseInsertOffset));
}
unsigned EndInsertOffset = BaseInsertOffset + 4 + UPad +
CPEMI->getOperand(2).getImm();
@@ -1417,8 +1421,8 @@ void ARMConstantIslands::createNewWater(unsigned CPUserIndex,
}
// We really must not split an IT block.
- DEBUG(unsigned PredReg;
- assert(!isThumb || getITInstrPredicate(*MI, PredReg) == ARMCC::AL));
+ LLVM_DEBUG(unsigned PredReg; assert(
+ !isThumb || getITInstrPredicate(*MI, PredReg) == ARMCC::AL));
NewMBB = splitBlockBeforeInstr(&*MI);
}
@@ -1452,7 +1456,7 @@ bool ARMConstantIslands::handleConstantPoolUser(unsigned CPUserIndex,
MachineBasicBlock *NewMBB;
water_iterator IP;
if (findAvailableWater(U, UserOffset, IP, CloserWater)) {
- DEBUG(dbgs() << "Found water in range\n");
+ LLVM_DEBUG(dbgs() << "Found water in range\n");
MachineBasicBlock *WaterBB = *IP;
// If the original WaterList entry was "new water" on this iteration,
@@ -1465,7 +1469,7 @@ bool ARMConstantIslands::handleConstantPoolUser(unsigned CPUserIndex,
NewMBB = &*++WaterBB->getIterator();
} else {
// No water found.
- DEBUG(dbgs() << "No water found\n");
+ LLVM_DEBUG(dbgs() << "No water found\n");
createNewWater(CPUserIndex, UserOffset, NewMBB);
// splitBlockBeforeInstr adds to WaterList, which is important when it is
@@ -1481,6 +1485,12 @@ bool ARMConstantIslands::handleConstantPoolUser(unsigned CPUserIndex,
// We are adding new water. Update NewWaterList.
NewWaterList.insert(NewIsland);
}
+ // Always align the new block because CP entries can be smaller than 4
+ // bytes. Be careful not to decrease the existing alignment, e.g. NewMBB may
+ // be an already aligned constant pool block.
+ const unsigned Align = isThumb ? 1 : 2;
+ if (NewMBB->getAlignment() < Align)
+ NewMBB->setAlignment(Align);
// Remove the original WaterList entry; we want subsequent insertions in
// this vicinity to go after the one we're about to insert. This
@@ -1522,8 +1532,9 @@ bool ARMConstantIslands::handleConstantPoolUser(unsigned CPUserIndex,
break;
}
- DEBUG(dbgs() << " Moved CPE to #" << ID << " CPI=" << CPI
- << format(" offset=%#x\n", BBInfo[NewIsland->getNumber()].Offset));
+ LLVM_DEBUG(
+ dbgs() << " Moved CPE to #" << ID << " CPI=" << CPI
+ << format(" offset=%#x\n", BBInfo[NewIsland->getNumber()].Offset));
return true;
}
@@ -1578,11 +1589,11 @@ bool ARMConstantIslands::isBBInRange(MachineInstr *MI,MachineBasicBlock *DestBB,
unsigned BrOffset = getOffsetOf(MI) + PCAdj;
unsigned DestOffset = BBInfo[DestBB->getNumber()].Offset;
- DEBUG(dbgs() << "Branch of destination " << printMBBReference(*DestBB)
- << " from " << printMBBReference(*MI->getParent())
- << " max delta=" << MaxDisp << " from " << getOffsetOf(MI)
- << " to " << DestOffset << " offset "
- << int(DestOffset - BrOffset) << "\t" << *MI);
+ LLVM_DEBUG(dbgs() << "Branch of destination " << printMBBReference(*DestBB)
+ << " from " << printMBBReference(*MI->getParent())
+ << " max delta=" << MaxDisp << " from " << getOffsetOf(MI)
+ << " to " << DestOffset << " offset "
+ << int(DestOffset - BrOffset) << "\t" << *MI);
if (BrOffset <= DestOffset) {
// Branch before the Dest.
@@ -1629,7 +1640,7 @@ ARMConstantIslands::fixupUnconditionalBr(ImmBranch &Br) {
HasFarJump = true;
++NumUBrFixed;
- DEBUG(dbgs() << " Changed B to long jump " << *MI);
+ LLVM_DEBUG(dbgs() << " Changed B to long jump " << *MI);
return true;
}
@@ -1673,8 +1684,9 @@ ARMConstantIslands::fixupConditionalBr(ImmBranch &Br) {
// b L1
MachineBasicBlock *NewDest = BMI->getOperand(0).getMBB();
if (isBBInRange(MI, NewDest, Br.MaxDisp)) {
- DEBUG(dbgs() << " Invert Bcc condition and swap its destination with "
- << *BMI);
+ LLVM_DEBUG(
+ dbgs() << " Invert Bcc condition and swap its destination with "
+ << *BMI);
BMI->getOperand(0).setMBB(DestBB);
MI->getOperand(0).setMBB(NewDest);
MI->getOperand(1).setImm(CC);
@@ -1700,9 +1712,9 @@ ARMConstantIslands::fixupConditionalBr(ImmBranch &Br) {
}
MachineBasicBlock *NextBB = &*++MBB->getIterator();
- DEBUG(dbgs() << " Insert B to " << printMBBReference(*DestBB)
- << " also invert condition and change dest. to "
- << printMBBReference(*NextBB) << "\n");
+ LLVM_DEBUG(dbgs() << " Insert B to " << printMBBReference(*DestBB)
+ << " also invert condition and change dest. to "
+ << printMBBReference(*NextBB) << "\n");
// Insert a new conditional branch and a new unconditional branch.
// Also update the ImmBranch as well as adding a new entry for the new branch.
@@ -1795,7 +1807,7 @@ bool ARMConstantIslands::optimizeThumb2Instructions() {
// FIXME: Check if offset is multiple of scale if scale is not 4.
if (isCPEntryInRange(U.MI, UserOffset, U.CPEMI, MaxOffs, false, true)) {
- DEBUG(dbgs() << "Shrink: " << *U.MI);
+ LLVM_DEBUG(dbgs() << "Shrink: " << *U.MI);
U.MI->setDesc(TII->get(NewOpc));
MachineBasicBlock *MBB = U.MI->getParent();
BBInfo[MBB->getNumber()].Size -= 2;
@@ -1839,7 +1851,7 @@ bool ARMConstantIslands::optimizeThumb2Branches() {
unsigned MaxOffs = ((1 << (Bits-1))-1) * Scale;
MachineBasicBlock *DestBB = Br.MI->getOperand(0).getMBB();
if (isBBInRange(Br.MI, DestBB, MaxOffs)) {
- DEBUG(dbgs() << "Shrink branch: " << *Br.MI);
+ LLVM_DEBUG(dbgs() << "Shrink branch: " << *Br.MI);
Br.MI->setDesc(TII->get(NewOpc));
MachineBasicBlock *MBB = Br.MI->getParent();
BBInfo[MBB->getNumber()].Size -= 2;
@@ -1883,7 +1895,7 @@ bool ARMConstantIslands::optimizeThumb2Branches() {
CmpMI->getOperand(1).getImm() == 0 &&
isARMLowRegister(Reg)) {
MachineBasicBlock *MBB = Br.MI->getParent();
- DEBUG(dbgs() << "Fold: " << *CmpMI << " and: " << *Br.MI);
+ LLVM_DEBUG(dbgs() << "Fold: " << *CmpMI << " and: " << *Br.MI);
MachineInstr *NewBR =
BuildMI(*MBB, CmpMI, Br.MI->getDebugLoc(), TII->get(NewOpc))
.addReg(Reg).addMBB(DestBB,Br.MI->getOperand(0).getTargetFlags());
@@ -1918,7 +1930,7 @@ static bool isSimpleIndexCalc(MachineInstr &I, unsigned EntryReg,
return true;
}
-/// \brief While trying to form a TBB/TBH instruction, we may (if the table
+/// While trying to form a TBB/TBH instruction, we may (if the table
/// doesn't immediately follow the BR_JT) need access to the start of the
/// jump-table. We know one instruction that produces such a register; this
/// function works out whether that definition can be preserved to the BR_JT,
@@ -2006,7 +2018,7 @@ bool ARMConstantIslands::preserveBaseRegister(MachineInstr *JumpMI,
return true;
}
-/// \brief Returns whether CPEMI is the first instruction in the block
+/// Returns whether CPEMI is the first instruction in the block
/// immediately following JTMI (assumed to be a TBB or TBH terminator). If so,
/// we can switch the first register to PC and usually remove the address
/// calculation that preceded it.
@@ -2052,7 +2064,7 @@ static void RemoveDeadAddBetweenLEAAndJT(MachineInstr *LEAMI,
}
}
- DEBUG(dbgs() << "Removing Dead Add: " << *RemovableAdd);
+ LLVM_DEBUG(dbgs() << "Removing Dead Add: " << *RemovableAdd);
RemovableAdd->eraseFromParent();
DeadSize += 4;
}
@@ -2198,7 +2210,7 @@ bool ARMConstantIslands::optimizeThumb2JumpTables() {
DeadSize += 4;
}
- DEBUG(dbgs() << "Shrink JT: " << *MI);
+ LLVM_DEBUG(dbgs() << "Shrink JT: " << *MI);
MachineInstr *CPEMI = User.CPEMI;
unsigned Opc = ByteOk ? ARM::t2TBB_JT : ARM::t2TBH_JT;
if (!isThumb2)
@@ -2212,7 +2224,7 @@ bool ARMConstantIslands::optimizeThumb2JumpTables() {
.addReg(IdxReg, getKillRegState(IdxRegKill))
.addJumpTableIndex(JTI, JTOP.getTargetFlags())
.addImm(CPEMI->getOperand(0).getImm());
- DEBUG(dbgs() << printMBBReference(*MBB) << ": " << *NewJTMI);
+ LLVM_DEBUG(dbgs() << printMBBReference(*MBB) << ": " << *NewJTMI);
unsigned JTOpc = ByteOk ? ARM::JUMPTABLE_TBB : ARM::JUMPTABLE_TBH;
CPEMI->setDesc(TII->get(JTOpc));
diff --git a/lib/Target/ARM/ARMConstantPoolValue.cpp b/lib/Target/ARM/ARMConstantPoolValue.cpp
index 39ae02af513b..236c4fab2a5c 100644
--- a/lib/Target/ARM/ARMConstantPoolValue.cpp
+++ b/lib/Target/ARM/ARMConstantPoolValue.cpp
@@ -14,6 +14,7 @@
#include "ARMConstantPoolValue.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
+#include "llvm/Config/llvm-config.h"
#include "llvm/IR/Constant.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/GlobalValue.h"
diff --git a/lib/Target/ARM/ARMExpandPseudoInsts.cpp b/lib/Target/ARM/ARMExpandPseudoInsts.cpp
index b14b2c6a813f..5dac6ec0b799 100644
--- a/lib/Target/ARM/ARMExpandPseudoInsts.cpp
+++ b/lib/Target/ARM/ARMExpandPseudoInsts.cpp
@@ -110,6 +110,9 @@ namespace {
// OddDblSpc depending on the lane number operand.
enum NEONRegSpacing {
SingleSpc,
+ SingleLowSpc , // Single spacing, low registers, three and four vectors.
+ SingleHighQSpc, // Single spacing, high registers, four vectors.
+ SingleHighTSpc, // Single spacing, high registers, three vectors.
EvenDblSpc,
OddDblSpc
};
@@ -154,10 +157,41 @@ static const NEONLdStTableEntry NEONLdStTable[] = {
{ ARM::VLD1LNq8Pseudo, ARM::VLD1LNd8, true, false, false, EvenDblSpc, 1, 8 ,true},
{ ARM::VLD1LNq8Pseudo_UPD, ARM::VLD1LNd8_UPD, true, true, true, EvenDblSpc, 1, 8 ,true},
+{ ARM::VLD1d16QPseudo, ARM::VLD1d16Q, true, false, false, SingleSpc, 4, 4 ,false},
+{ ARM::VLD1d16TPseudo, ARM::VLD1d16T, true, false, false, SingleSpc, 3, 4 ,false},
+{ ARM::VLD1d32QPseudo, ARM::VLD1d32Q, true, false, false, SingleSpc, 4, 2 ,false},
+{ ARM::VLD1d32TPseudo, ARM::VLD1d32T, true, false, false, SingleSpc, 3, 2 ,false},
{ ARM::VLD1d64QPseudo, ARM::VLD1d64Q, true, false, false, SingleSpc, 4, 1 ,false},
{ ARM::VLD1d64QPseudoWB_fixed, ARM::VLD1d64Qwb_fixed, true, true, false, SingleSpc, 4, 1 ,false},
+{ ARM::VLD1d64QPseudoWB_register, ARM::VLD1d64Qwb_register, true, true, true, SingleSpc, 4, 1 ,false},
{ ARM::VLD1d64TPseudo, ARM::VLD1d64T, true, false, false, SingleSpc, 3, 1 ,false},
{ ARM::VLD1d64TPseudoWB_fixed, ARM::VLD1d64Twb_fixed, true, true, false, SingleSpc, 3, 1 ,false},
+{ ARM::VLD1d64TPseudoWB_register, ARM::VLD1d64Twb_register, true, true, true, SingleSpc, 3, 1 ,false},
+{ ARM::VLD1d8QPseudo, ARM::VLD1d8Q, true, false, false, SingleSpc, 4, 8 ,false},
+{ ARM::VLD1d8TPseudo, ARM::VLD1d8T, true, false, false, SingleSpc, 3, 8 ,false},
+{ ARM::VLD1q16HighQPseudo, ARM::VLD1d16Q, true, false, false, SingleHighQSpc, 4, 4 ,false},
+{ ARM::VLD1q16HighTPseudo, ARM::VLD1d16T, true, false, false, SingleHighTSpc, 3, 4 ,false},
+{ ARM::VLD1q16LowQPseudo_UPD, ARM::VLD1d16Qwb_fixed, true, true, true, SingleLowSpc, 4, 4 ,false},
+{ ARM::VLD1q16LowTPseudo_UPD, ARM::VLD1d16Twb_fixed, true, true, true, SingleLowSpc, 3, 4 ,false},
+{ ARM::VLD1q32HighQPseudo, ARM::VLD1d32Q, true, false, false, SingleHighQSpc, 4, 2 ,false},
+{ ARM::VLD1q32HighTPseudo, ARM::VLD1d32T, true, false, false, SingleHighTSpc, 3, 2 ,false},
+{ ARM::VLD1q32LowQPseudo_UPD, ARM::VLD1d32Qwb_fixed, true, true, true, SingleLowSpc, 4, 2 ,false},
+{ ARM::VLD1q32LowTPseudo_UPD, ARM::VLD1d32Twb_fixed, true, true, true, SingleLowSpc, 3, 2 ,false},
+{ ARM::VLD1q64HighQPseudo, ARM::VLD1d64Q, true, false, false, SingleHighQSpc, 4, 1 ,false},
+{ ARM::VLD1q64HighTPseudo, ARM::VLD1d64T, true, false, false, SingleHighTSpc, 3, 1 ,false},
+{ ARM::VLD1q64LowQPseudo_UPD, ARM::VLD1d64Qwb_fixed, true, true, true, SingleLowSpc, 4, 1 ,false},
+{ ARM::VLD1q64LowTPseudo_UPD, ARM::VLD1d64Twb_fixed, true, true, true, SingleLowSpc, 3, 1 ,false},
+{ ARM::VLD1q8HighQPseudo, ARM::VLD1d8Q, true, false, false, SingleHighQSpc, 4, 8 ,false},
+{ ARM::VLD1q8HighTPseudo, ARM::VLD1d8T, true, false, false, SingleHighTSpc, 3, 8 ,false},
+{ ARM::VLD1q8LowQPseudo_UPD, ARM::VLD1d8Qwb_fixed, true, true, true, SingleLowSpc, 4, 8 ,false},
+{ ARM::VLD1q8LowTPseudo_UPD, ARM::VLD1d8Twb_fixed, true, true, true, SingleLowSpc, 3, 8 ,false},
+
+{ ARM::VLD2DUPq16EvenPseudo, ARM::VLD2DUPd16x2, true, false, false, EvenDblSpc, 2, 4 ,false},
+{ ARM::VLD2DUPq16OddPseudo, ARM::VLD2DUPd16x2, true, false, false, OddDblSpc, 2, 4 ,false},
+{ ARM::VLD2DUPq32EvenPseudo, ARM::VLD2DUPd32x2, true, false, false, EvenDblSpc, 2, 2 ,false},
+{ ARM::VLD2DUPq32OddPseudo, ARM::VLD2DUPd32x2, true, false, false, OddDblSpc, 2, 2 ,false},
+{ ARM::VLD2DUPq8EvenPseudo, ARM::VLD2DUPd8x2, true, false, false, EvenDblSpc, 2, 8 ,false},
+{ ARM::VLD2DUPq8OddPseudo, ARM::VLD2DUPd8x2, true, false, false, OddDblSpc, 2, 8 ,false},
{ ARM::VLD2LNd16Pseudo, ARM::VLD2LNd16, true, false, false, SingleSpc, 2, 4 ,true},
{ ARM::VLD2LNd16Pseudo_UPD, ARM::VLD2LNd16_UPD, true, true, true, SingleSpc, 2, 4 ,true},
@@ -186,6 +220,12 @@ static const NEONLdStTableEntry NEONLdStTable[] = {
{ ARM::VLD3DUPd32Pseudo_UPD, ARM::VLD3DUPd32_UPD, true, true, true, SingleSpc, 3, 2,true},
{ ARM::VLD3DUPd8Pseudo, ARM::VLD3DUPd8, true, false, false, SingleSpc, 3, 8,true},
{ ARM::VLD3DUPd8Pseudo_UPD, ARM::VLD3DUPd8_UPD, true, true, true, SingleSpc, 3, 8,true},
+{ ARM::VLD3DUPq16EvenPseudo, ARM::VLD3DUPq16, true, false, false, EvenDblSpc, 3, 4 ,true},
+{ ARM::VLD3DUPq16OddPseudo, ARM::VLD3DUPq16, true, false, false, OddDblSpc, 3, 4 ,true},
+{ ARM::VLD3DUPq32EvenPseudo, ARM::VLD3DUPq32, true, false, false, EvenDblSpc, 3, 2 ,true},
+{ ARM::VLD3DUPq32OddPseudo, ARM::VLD3DUPq32, true, false, false, OddDblSpc, 3, 2 ,true},
+{ ARM::VLD3DUPq8EvenPseudo, ARM::VLD3DUPq8, true, false, false, EvenDblSpc, 3, 8 ,true},
+{ ARM::VLD3DUPq8OddPseudo, ARM::VLD3DUPq8, true, false, false, OddDblSpc, 3, 8 ,true},
{ ARM::VLD3LNd16Pseudo, ARM::VLD3LNd16, true, false, false, SingleSpc, 3, 4 ,true},
{ ARM::VLD3LNd16Pseudo_UPD, ARM::VLD3LNd16_UPD, true, true, true, SingleSpc, 3, 4 ,true},
@@ -221,6 +261,12 @@ static const NEONLdStTableEntry NEONLdStTable[] = {
{ ARM::VLD4DUPd32Pseudo_UPD, ARM::VLD4DUPd32_UPD, true, true, true, SingleSpc, 4, 2,true},
{ ARM::VLD4DUPd8Pseudo, ARM::VLD4DUPd8, true, false, false, SingleSpc, 4, 8,true},
{ ARM::VLD4DUPd8Pseudo_UPD, ARM::VLD4DUPd8_UPD, true, true, true, SingleSpc, 4, 8,true},
+{ ARM::VLD4DUPq16EvenPseudo, ARM::VLD4DUPq16, true, false, false, EvenDblSpc, 4, 4 ,true},
+{ ARM::VLD4DUPq16OddPseudo, ARM::VLD4DUPq16, true, false, false, OddDblSpc, 4, 4 ,true},
+{ ARM::VLD4DUPq32EvenPseudo, ARM::VLD4DUPq32, true, false, false, EvenDblSpc, 4, 2 ,true},
+{ ARM::VLD4DUPq32OddPseudo, ARM::VLD4DUPq32, true, false, false, OddDblSpc, 4, 2 ,true},
+{ ARM::VLD4DUPq8EvenPseudo, ARM::VLD4DUPq8, true, false, false, EvenDblSpc, 4, 8 ,true},
+{ ARM::VLD4DUPq8OddPseudo, ARM::VLD4DUPq8, true, false, false, OddDblSpc, 4, 8 ,true},
{ ARM::VLD4LNd16Pseudo, ARM::VLD4LNd16, true, false, false, SingleSpc, 4, 4 ,true},
{ ARM::VLD4LNd16Pseudo_UPD, ARM::VLD4LNd16_UPD, true, true, true, SingleSpc, 4, 4 ,true},
@@ -257,12 +303,34 @@ static const NEONLdStTableEntry NEONLdStTable[] = {
{ ARM::VST1LNq8Pseudo, ARM::VST1LNd8, false, false, false, EvenDblSpc, 1, 8 ,true},
{ ARM::VST1LNq8Pseudo_UPD, ARM::VST1LNd8_UPD, false, true, true, EvenDblSpc, 1, 8 ,true},
+{ ARM::VST1d16QPseudo, ARM::VST1d16Q, false, false, false, SingleSpc, 4, 4 ,false},
+{ ARM::VST1d16TPseudo, ARM::VST1d16T, false, false, false, SingleSpc, 3, 4 ,false},
+{ ARM::VST1d32QPseudo, ARM::VST1d32Q, false, false, false, SingleSpc, 4, 2 ,false},
+{ ARM::VST1d32TPseudo, ARM::VST1d32T, false, false, false, SingleSpc, 3, 2 ,false},
{ ARM::VST1d64QPseudo, ARM::VST1d64Q, false, false, false, SingleSpc, 4, 1 ,false},
{ ARM::VST1d64QPseudoWB_fixed, ARM::VST1d64Qwb_fixed, false, true, false, SingleSpc, 4, 1 ,false},
{ ARM::VST1d64QPseudoWB_register, ARM::VST1d64Qwb_register, false, true, true, SingleSpc, 4, 1 ,false},
{ ARM::VST1d64TPseudo, ARM::VST1d64T, false, false, false, SingleSpc, 3, 1 ,false},
{ ARM::VST1d64TPseudoWB_fixed, ARM::VST1d64Twb_fixed, false, true, false, SingleSpc, 3, 1 ,false},
{ ARM::VST1d64TPseudoWB_register, ARM::VST1d64Twb_register, false, true, true, SingleSpc, 3, 1 ,false},
+{ ARM::VST1d8QPseudo, ARM::VST1d8Q, false, false, false, SingleSpc, 4, 8 ,false},
+{ ARM::VST1d8TPseudo, ARM::VST1d8T, false, false, false, SingleSpc, 3, 8 ,false},
+{ ARM::VST1q16HighQPseudo, ARM::VST1d16Q, false, false, false, SingleHighQSpc, 4, 4 ,false},
+{ ARM::VST1q16HighTPseudo, ARM::VST1d16T, false, false, false, SingleHighTSpc, 3, 4 ,false},
+{ ARM::VST1q16LowQPseudo_UPD, ARM::VST1d16Qwb_fixed, false, true, true, SingleLowSpc, 4, 4 ,false},
+{ ARM::VST1q16LowTPseudo_UPD, ARM::VST1d16Twb_fixed, false, true, true, SingleLowSpc, 3, 4 ,false},
+{ ARM::VST1q32HighQPseudo, ARM::VST1d32Q, false, false, false, SingleHighQSpc, 4, 2 ,false},
+{ ARM::VST1q32HighTPseudo, ARM::VST1d32T, false, false, false, SingleHighTSpc, 3, 2 ,false},
+{ ARM::VST1q32LowQPseudo_UPD, ARM::VST1d32Qwb_fixed, false, true, true, SingleLowSpc, 4, 2 ,false},
+{ ARM::VST1q32LowTPseudo_UPD, ARM::VST1d32Twb_fixed, false, true, true, SingleLowSpc, 3, 2 ,false},
+{ ARM::VST1q64HighQPseudo, ARM::VST1d64Q, false, false, false, SingleHighQSpc, 4, 1 ,false},
+{ ARM::VST1q64HighTPseudo, ARM::VST1d64T, false, false, false, SingleHighTSpc, 3, 1 ,false},
+{ ARM::VST1q64LowQPseudo_UPD, ARM::VST1d64Qwb_fixed, false, true, true, SingleLowSpc, 4, 1 ,false},
+{ ARM::VST1q64LowTPseudo_UPD, ARM::VST1d64Twb_fixed, false, true, true, SingleLowSpc, 3, 1 ,false},
+{ ARM::VST1q8HighQPseudo, ARM::VST1d8Q, false, false, false, SingleHighQSpc, 4, 8 ,false},
+{ ARM::VST1q8HighTPseudo, ARM::VST1d8T, false, false, false, SingleHighTSpc, 3, 8 ,false},
+{ ARM::VST1q8LowQPseudo_UPD, ARM::VST1d8Qwb_fixed, false, true, true, SingleLowSpc, 4, 8 ,false},
+{ ARM::VST1q8LowTPseudo_UPD, ARM::VST1d8Twb_fixed, false, true, true, SingleLowSpc, 3, 8 ,false},
{ ARM::VST2LNd16Pseudo, ARM::VST2LNd16, false, false, false, SingleSpc, 2, 4 ,true},
{ ARM::VST2LNd16Pseudo_UPD, ARM::VST2LNd16_UPD, false, true, true, SingleSpc, 2, 4 ,true},
@@ -347,11 +415,11 @@ static const NEONLdStTableEntry NEONLdStTable[] = {
static const NEONLdStTableEntry *LookupNEONLdSt(unsigned Opcode) {
#ifndef NDEBUG
// Make sure the table is sorted.
- static bool TableChecked = false;
- if (!TableChecked) {
+ static std::atomic<bool> TableChecked(false);
+ if (!TableChecked.load(std::memory_order_relaxed)) {
assert(std::is_sorted(std::begin(NEONLdStTable), std::end(NEONLdStTable)) &&
"NEONLdStTable is not sorted!");
- TableChecked = true;
+ TableChecked.store(true, std::memory_order_relaxed);
}
#endif
@@ -368,11 +436,21 @@ static const NEONLdStTableEntry *LookupNEONLdSt(unsigned Opcode) {
static void GetDSubRegs(unsigned Reg, NEONRegSpacing RegSpc,
const TargetRegisterInfo *TRI, unsigned &D0,
unsigned &D1, unsigned &D2, unsigned &D3) {
- if (RegSpc == SingleSpc) {
+ if (RegSpc == SingleSpc || RegSpc == SingleLowSpc) {
D0 = TRI->getSubReg(Reg, ARM::dsub_0);
D1 = TRI->getSubReg(Reg, ARM::dsub_1);
D2 = TRI->getSubReg(Reg, ARM::dsub_2);
D3 = TRI->getSubReg(Reg, ARM::dsub_3);
+ } else if (RegSpc == SingleHighQSpc) {
+ D0 = TRI->getSubReg(Reg, ARM::dsub_4);
+ D1 = TRI->getSubReg(Reg, ARM::dsub_5);
+ D2 = TRI->getSubReg(Reg, ARM::dsub_6);
+ D3 = TRI->getSubReg(Reg, ARM::dsub_7);
+ } else if (RegSpc == SingleHighTSpc) {
+ D0 = TRI->getSubReg(Reg, ARM::dsub_3);
+ D1 = TRI->getSubReg(Reg, ARM::dsub_4);
+ D2 = TRI->getSubReg(Reg, ARM::dsub_5);
+ D3 = TRI->getSubReg(Reg, ARM::dsub_6);
} else if (RegSpc == EvenDblSpc) {
D0 = TRI->getSubReg(Reg, ARM::dsub_0);
D1 = TRI->getSubReg(Reg, ARM::dsub_2);
@@ -404,15 +482,31 @@ void ARMExpandPseudo::ExpandVLD(MachineBasicBlock::iterator &MBBI) {
bool DstIsDead = MI.getOperand(OpIdx).isDead();
unsigned DstReg = MI.getOperand(OpIdx++).getReg();
- unsigned D0, D1, D2, D3;
- GetDSubRegs(DstReg, RegSpc, TRI, D0, D1, D2, D3);
- MIB.addReg(D0, RegState::Define | getDeadRegState(DstIsDead));
- if (NumRegs > 1 && TableEntry->copyAllListRegs)
- MIB.addReg(D1, RegState::Define | getDeadRegState(DstIsDead));
- if (NumRegs > 2 && TableEntry->copyAllListRegs)
- MIB.addReg(D2, RegState::Define | getDeadRegState(DstIsDead));
- if (NumRegs > 3 && TableEntry->copyAllListRegs)
- MIB.addReg(D3, RegState::Define | getDeadRegState(DstIsDead));
+ if(TableEntry->RealOpc == ARM::VLD2DUPd8x2 ||
+ TableEntry->RealOpc == ARM::VLD2DUPd16x2 ||
+ TableEntry->RealOpc == ARM::VLD2DUPd32x2) {
+ unsigned SubRegIndex;
+ if (RegSpc == EvenDblSpc) {
+ SubRegIndex = ARM::dsub_0;
+ } else {
+ assert(RegSpc == OddDblSpc && "Unexpected spacing!");
+ SubRegIndex = ARM::dsub_1;
+ }
+ unsigned SubReg = TRI->getSubReg(DstReg, SubRegIndex);
+ unsigned DstRegPair = TRI->getMatchingSuperReg(SubReg, ARM::dsub_0,
+ &ARM::DPairSpcRegClass);
+ MIB.addReg(DstRegPair, RegState::Define | getDeadRegState(DstIsDead));
+ } else {
+ unsigned D0, D1, D2, D3;
+ GetDSubRegs(DstReg, RegSpc, TRI, D0, D1, D2, D3);
+ MIB.addReg(D0, RegState::Define | getDeadRegState(DstIsDead));
+ if (NumRegs > 1 && TableEntry->copyAllListRegs)
+ MIB.addReg(D1, RegState::Define | getDeadRegState(DstIsDead));
+ if (NumRegs > 2 && TableEntry->copyAllListRegs)
+ MIB.addReg(D2, RegState::Define | getDeadRegState(DstIsDead));
+ if (NumRegs > 3 && TableEntry->copyAllListRegs)
+ MIB.addReg(D3, RegState::Define | getDeadRegState(DstIsDead));
+ }
if (TableEntry->isUpdating)
MIB.add(MI.getOperand(OpIdx++));
@@ -420,16 +514,45 @@ void ARMExpandPseudo::ExpandVLD(MachineBasicBlock::iterator &MBBI) {
// Copy the addrmode6 operands.
MIB.add(MI.getOperand(OpIdx++));
MIB.add(MI.getOperand(OpIdx++));
+
// Copy the am6offset operand.
- if (TableEntry->hasWritebackOperand)
- MIB.add(MI.getOperand(OpIdx++));
+ if (TableEntry->hasWritebackOperand) {
+ // TODO: The writing-back pseudo instructions we translate here are all
+ // defined to take am6offset nodes that are capable to represent both fixed
+ // and register forms. Some real instructions, however, do not rely on
+ // am6offset and have separate definitions for such forms. When this is the
+ // case, fixed forms do not take any offset nodes, so here we skip them for
+ // such instructions. Once all real and pseudo writing-back instructions are
+ // rewritten without use of am6offset nodes, this code will go away.
+ const MachineOperand &AM6Offset = MI.getOperand(OpIdx++);
+ if (TableEntry->RealOpc == ARM::VLD1d8Qwb_fixed ||
+ TableEntry->RealOpc == ARM::VLD1d16Qwb_fixed ||
+ TableEntry->RealOpc == ARM::VLD1d32Qwb_fixed ||
+ TableEntry->RealOpc == ARM::VLD1d64Qwb_fixed ||
+ TableEntry->RealOpc == ARM::VLD1d8Twb_fixed ||
+ TableEntry->RealOpc == ARM::VLD1d16Twb_fixed ||
+ TableEntry->RealOpc == ARM::VLD1d32Twb_fixed ||
+ TableEntry->RealOpc == ARM::VLD1d64Twb_fixed) {
+ assert(AM6Offset.getReg() == 0 &&
+ "A fixed writing-back pseudo instruction provides an offset "
+ "register!");
+ } else {
+ MIB.add(AM6Offset);
+ }
+ }
// For an instruction writing double-spaced subregs, the pseudo instruction
// has an extra operand that is a use of the super-register. Record the
// operand index and skip over it.
unsigned SrcOpIdx = 0;
- if (RegSpc == EvenDblSpc || RegSpc == OddDblSpc)
- SrcOpIdx = OpIdx++;
+ if(TableEntry->RealOpc != ARM::VLD2DUPd8x2 &&
+ TableEntry->RealOpc != ARM::VLD2DUPd16x2 &&
+ TableEntry->RealOpc != ARM::VLD2DUPd32x2) {
+ if (RegSpc == EvenDblSpc || RegSpc == OddDblSpc ||
+ RegSpc == SingleLowSpc || RegSpc == SingleHighQSpc ||
+ RegSpc == SingleHighTSpc)
+ SrcOpIdx = OpIdx++;
+ }
// Copy the predicate operands.
MIB.add(MI.getOperand(OpIdx++));
@@ -472,9 +595,31 @@ void ARMExpandPseudo::ExpandVST(MachineBasicBlock::iterator &MBBI) {
// Copy the addrmode6 operands.
MIB.add(MI.getOperand(OpIdx++));
MIB.add(MI.getOperand(OpIdx++));
- // Copy the am6offset operand.
- if (TableEntry->hasWritebackOperand)
- MIB.add(MI.getOperand(OpIdx++));
+
+ if (TableEntry->hasWritebackOperand) {
+ // TODO: The writing-back pseudo instructions we translate here are all
+ // defined to take am6offset nodes that are capable to represent both fixed
+ // and register forms. Some real instructions, however, do not rely on
+ // am6offset and have separate definitions for such forms. When this is the
+ // case, fixed forms do not take any offset nodes, so here we skip them for
+ // such instructions. Once all real and pseudo writing-back instructions are
+ // rewritten without use of am6offset nodes, this code will go away.
+ const MachineOperand &AM6Offset = MI.getOperand(OpIdx++);
+ if (TableEntry->RealOpc == ARM::VST1d8Qwb_fixed ||
+ TableEntry->RealOpc == ARM::VST1d16Qwb_fixed ||
+ TableEntry->RealOpc == ARM::VST1d32Qwb_fixed ||
+ TableEntry->RealOpc == ARM::VST1d64Qwb_fixed ||
+ TableEntry->RealOpc == ARM::VST1d8Twb_fixed ||
+ TableEntry->RealOpc == ARM::VST1d16Twb_fixed ||
+ TableEntry->RealOpc == ARM::VST1d32Twb_fixed ||
+ TableEntry->RealOpc == ARM::VST1d64Twb_fixed) {
+ assert(AM6Offset.getReg() == 0 &&
+ "A fixed writing-back pseudo instruction provides an offset "
+ "register!");
+ } else {
+ MIB.add(AM6Offset);
+ }
+ }
bool SrcIsKill = MI.getOperand(OpIdx).isKill();
bool SrcIsUndef = MI.getOperand(OpIdx).isUndef();
@@ -608,7 +753,6 @@ void ARMExpandPseudo::ExpandVTBL(MachineBasicBlock::iterator &MBBI,
MIB.add(MI.getOperand(OpIdx++));
if (IsExt) {
MachineOperand VdSrc(MI.getOperand(OpIdx++));
- VdSrc.setIsRenamable(false);
MIB.add(VdSrc);
}
@@ -620,7 +764,6 @@ void ARMExpandPseudo::ExpandVTBL(MachineBasicBlock::iterator &MBBI,
// Copy the other source register operand.
MachineOperand VmSrc(MI.getOperand(OpIdx++));
- VmSrc.setIsRenamable(false);
MIB.add(VmSrc);
// Copy the predicate operands.
@@ -1470,7 +1613,6 @@ bool ARMExpandPseudo::ExpandMI(MachineBasicBlock &MBB,
// Copy the destination register.
MachineOperand Dst(MI.getOperand(OpIdx++));
- Dst.setIsRenamable(false);
MIB.add(Dst);
// Copy the predicate operands.
@@ -1504,8 +1646,12 @@ bool ARMExpandPseudo::ExpandMI(MachineBasicBlock &MBB,
case ARM::VLD3d8Pseudo:
case ARM::VLD3d16Pseudo:
case ARM::VLD3d32Pseudo:
+ case ARM::VLD1d8TPseudo:
+ case ARM::VLD1d16TPseudo:
+ case ARM::VLD1d32TPseudo:
case ARM::VLD1d64TPseudo:
case ARM::VLD1d64TPseudoWB_fixed:
+ case ARM::VLD1d64TPseudoWB_register:
case ARM::VLD3d8Pseudo_UPD:
case ARM::VLD3d16Pseudo_UPD:
case ARM::VLD3d32Pseudo_UPD:
@@ -1521,8 +1667,28 @@ bool ARMExpandPseudo::ExpandMI(MachineBasicBlock &MBB,
case ARM::VLD4d8Pseudo:
case ARM::VLD4d16Pseudo:
case ARM::VLD4d32Pseudo:
+ case ARM::VLD1d8QPseudo:
+ case ARM::VLD1d16QPseudo:
+ case ARM::VLD1d32QPseudo:
case ARM::VLD1d64QPseudo:
case ARM::VLD1d64QPseudoWB_fixed:
+ case ARM::VLD1d64QPseudoWB_register:
+ case ARM::VLD1q8HighQPseudo:
+ case ARM::VLD1q8LowQPseudo_UPD:
+ case ARM::VLD1q8HighTPseudo:
+ case ARM::VLD1q8LowTPseudo_UPD:
+ case ARM::VLD1q16HighQPseudo:
+ case ARM::VLD1q16LowQPseudo_UPD:
+ case ARM::VLD1q16HighTPseudo:
+ case ARM::VLD1q16LowTPseudo_UPD:
+ case ARM::VLD1q32HighQPseudo:
+ case ARM::VLD1q32LowQPseudo_UPD:
+ case ARM::VLD1q32HighTPseudo:
+ case ARM::VLD1q32LowTPseudo_UPD:
+ case ARM::VLD1q64HighQPseudo:
+ case ARM::VLD1q64LowQPseudo_UPD:
+ case ARM::VLD1q64HighTPseudo:
+ case ARM::VLD1q64LowTPseudo_UPD:
case ARM::VLD4d8Pseudo_UPD:
case ARM::VLD4d16Pseudo_UPD:
case ARM::VLD4d32Pseudo_UPD:
@@ -1547,6 +1713,24 @@ bool ARMExpandPseudo::ExpandMI(MachineBasicBlock &MBB,
case ARM::VLD4DUPd8Pseudo_UPD:
case ARM::VLD4DUPd16Pseudo_UPD:
case ARM::VLD4DUPd32Pseudo_UPD:
+ case ARM::VLD2DUPq8EvenPseudo:
+ case ARM::VLD2DUPq8OddPseudo:
+ case ARM::VLD2DUPq16EvenPseudo:
+ case ARM::VLD2DUPq16OddPseudo:
+ case ARM::VLD2DUPq32EvenPseudo:
+ case ARM::VLD2DUPq32OddPseudo:
+ case ARM::VLD3DUPq8EvenPseudo:
+ case ARM::VLD3DUPq8OddPseudo:
+ case ARM::VLD3DUPq16EvenPseudo:
+ case ARM::VLD3DUPq16OddPseudo:
+ case ARM::VLD3DUPq32EvenPseudo:
+ case ARM::VLD3DUPq32OddPseudo:
+ case ARM::VLD4DUPq8EvenPseudo:
+ case ARM::VLD4DUPq8OddPseudo:
+ case ARM::VLD4DUPq16EvenPseudo:
+ case ARM::VLD4DUPq16OddPseudo:
+ case ARM::VLD4DUPq32EvenPseudo:
+ case ARM::VLD4DUPq32OddPseudo:
ExpandVLD(MBBI);
return true;
@@ -1562,6 +1746,9 @@ bool ARMExpandPseudo::ExpandMI(MachineBasicBlock &MBB,
case ARM::VST3d8Pseudo:
case ARM::VST3d16Pseudo:
case ARM::VST3d32Pseudo:
+ case ARM::VST1d8TPseudo:
+ case ARM::VST1d16TPseudo:
+ case ARM::VST1d32TPseudo:
case ARM::VST1d64TPseudo:
case ARM::VST3d8Pseudo_UPD:
case ARM::VST3d16Pseudo_UPD:
@@ -1580,12 +1767,31 @@ bool ARMExpandPseudo::ExpandMI(MachineBasicBlock &MBB,
case ARM::VST4d8Pseudo:
case ARM::VST4d16Pseudo:
case ARM::VST4d32Pseudo:
+ case ARM::VST1d8QPseudo:
+ case ARM::VST1d16QPseudo:
+ case ARM::VST1d32QPseudo:
case ARM::VST1d64QPseudo:
case ARM::VST4d8Pseudo_UPD:
case ARM::VST4d16Pseudo_UPD:
case ARM::VST4d32Pseudo_UPD:
case ARM::VST1d64QPseudoWB_fixed:
case ARM::VST1d64QPseudoWB_register:
+ case ARM::VST1q8HighQPseudo:
+ case ARM::VST1q8LowQPseudo_UPD:
+ case ARM::VST1q8HighTPseudo:
+ case ARM::VST1q8LowTPseudo_UPD:
+ case ARM::VST1q16HighQPseudo:
+ case ARM::VST1q16LowQPseudo_UPD:
+ case ARM::VST1q16HighTPseudo:
+ case ARM::VST1q16LowTPseudo_UPD:
+ case ARM::VST1q32HighQPseudo:
+ case ARM::VST1q32LowQPseudo_UPD:
+ case ARM::VST1q32HighTPseudo:
+ case ARM::VST1q32LowTPseudo_UPD:
+ case ARM::VST1q64HighQPseudo:
+ case ARM::VST1q64LowQPseudo_UPD:
+ case ARM::VST1q64HighTPseudo:
+ case ARM::VST1q64LowTPseudo_UPD:
case ARM::VST4q8Pseudo_UPD:
case ARM::VST4q16Pseudo_UPD:
case ARM::VST4q32Pseudo_UPD:
diff --git a/lib/Target/ARM/ARMFastISel.cpp b/lib/Target/ARM/ARMFastISel.cpp
index 60048d4453d8..26d4aaa12acf 100644
--- a/lib/Target/ARM/ARMFastISel.cpp
+++ b/lib/Target/ARM/ARMFastISel.cpp
@@ -41,7 +41,6 @@
#include "llvm/CodeGen/MachineMemOperand.h"
#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
-#include "llvm/CodeGen/MachineValueType.h"
#include "llvm/CodeGen/RuntimeLibcalls.h"
#include "llvm/CodeGen/TargetInstrInfo.h"
#include "llvm/CodeGen/TargetLowering.h"
@@ -75,6 +74,7 @@
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MachineValueType.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
@@ -2352,8 +2352,8 @@ bool ARMFastISel::SelectCall(const Instruction *I,
for (ImmutableCallSite::arg_iterator i = CS.arg_begin(), e = CS.arg_end();
i != e; ++i) {
// If we're lowering a memory intrinsic instead of a regular call, skip the
- // last two arguments, which shouldn't be passed to the underlying function.
- if (IntrMemName && e-i <= 2)
+ // last argument, which shouldn't be passed to the underlying function.
+ if (IntrMemName && e - i <= 1)
break;
ISD::ArgFlagsTy Flags;
@@ -2546,7 +2546,8 @@ bool ARMFastISel::SelectIntrinsicCall(const IntrinsicInst &I) {
if (!ARMComputeAddress(MTI.getRawDest(), Dest) ||
!ARMComputeAddress(MTI.getRawSource(), Src))
return false;
- unsigned Alignment = MTI.getAlignment();
+ unsigned Alignment = MinAlign(MTI.getDestAlignment(),
+ MTI.getSourceAlignment());
if (ARMTryEmitSmallMemCpy(Dest, Src, Len, Alignment))
return true;
}
@@ -2912,7 +2913,7 @@ static const struct FoldableLoadExtendsStruct {
{ { ARM::UXTB, ARM::t2UXTB }, 0, 1, MVT::i8 }
};
-/// \brief The specified machine instr operand is a vreg, and that
+/// The specified machine instr operand is a vreg, and that
/// vreg is being provided by the specified load instruction. If possible,
/// try to fold the load as an operand to the instruction, returning true if
/// successful.
diff --git a/lib/Target/ARM/ARMFrameLowering.cpp b/lib/Target/ARM/ARMFrameLowering.cpp
index 4ff864ac6ccd..af983ce2606a 100644
--- a/lib/Target/ARM/ARMFrameLowering.cpp
+++ b/lib/Target/ARM/ARMFrameLowering.cpp
@@ -87,6 +87,18 @@ bool ARMFrameLowering::noFramePointerElim(const MachineFunction &MF) const {
MF.getSubtarget<ARMSubtarget>().useFastISel();
}
+/// Returns true if the target can safely skip saving callee-saved registers
+/// for noreturn nounwind functions.
+bool ARMFrameLowering::enableCalleeSaveSkip(const MachineFunction &MF) const {
+ assert(MF.getFunction().hasFnAttribute(Attribute::NoReturn) &&
+ MF.getFunction().hasFnAttribute(Attribute::NoUnwind) &&
+ !MF.getFunction().hasFnAttribute(Attribute::UWTable));
+
+ // Frame pointer and link register are not treated as normal CSR, thus we
+ // can always skip CSR saves for nonreturning functions.
+ return true;
+}
+
/// hasFP - Return true if the specified function should have a dedicated frame
/// pointer register. This is true if the function has variable sized allocas
/// or if frame pointer elimination is disabled.
@@ -209,7 +221,8 @@ static bool WindowsRequiresStackProbe(const MachineFunction &MF,
F.getFnAttribute("stack-probe-size")
.getValueAsString()
.getAsInteger(0, StackProbeSize);
- return StackSizeInBytes >= StackProbeSize;
+ return (StackSizeInBytes >= StackProbeSize) &&
+ !F.hasFnAttribute("no-stack-arg-probe");
}
namespace {
@@ -918,15 +931,17 @@ ARMFrameLowering::ResolveFrameIndexReference(const MachineFunction &MF,
return FPOffset;
}
}
- } else if (AFI->isThumb2Function()) {
+ } else if (AFI->isThumbFunction()) {
+ // Prefer SP to base pointer, if the offset is suitably aligned and in
+ // range as the effective range of the immediate offset is bigger when
+ // basing off SP.
// Use add <rd>, sp, #<imm8>
// ldr <rd>, [sp, #<imm8>]
- // if at all possible to save space.
if (Offset >= 0 && (Offset & 3) == 0 && Offset <= 1020)
return Offset;
// In Thumb2 mode, the negative offset is very limited. Try to avoid
// out of range references. ldr <rt>,[<rn>, #-<imm8>]
- if (FPOffset >= -255 && FPOffset < 0) {
+ if (AFI->isThumb2Function() && FPOffset >= -255 && FPOffset < 0) {
FrameReg = RegInfo->getFrameRegister(MF);
return FPOffset;
}
@@ -991,8 +1006,8 @@ void ARMFrameLowering::emitPushInst(MachineBasicBlock &MBB,
if (Regs.empty())
continue;
- std::sort(Regs.begin(), Regs.end(), [&](const RegAndKill &LHS,
- const RegAndKill &RHS) {
+ llvm::sort(Regs.begin(), Regs.end(), [&](const RegAndKill &LHS,
+ const RegAndKill &RHS) {
return TRI.getEncodingValue(LHS.first) < TRI.getEncodingValue(RHS.first);
});
@@ -1065,6 +1080,7 @@ void ARMFrameLowering::emitPopInst(MachineBasicBlock &MBB,
!isTrap && STI.hasV5TOps()) {
if (MBB.succ_empty()) {
Reg = ARM::PC;
+ // Fold the return instruction into the LDM.
DeleteRet = true;
LdmOpc = AFI->isThumbFunction() ? ARM::t2LDMIA_RET : ARM::LDMIA_RET;
// We 'restore' LR into PC so it is not live out of the return block:
@@ -1072,7 +1088,6 @@ void ARMFrameLowering::emitPopInst(MachineBasicBlock &MBB,
Info.setRestored(false);
} else
LdmOpc = AFI->isThumbFunction() ? ARM::t2LDMIA_UPD : ARM::LDMIA_UPD;
- // Fold the return instruction into the LDM.
}
// If NoGap is true, pop consecutive registers and then leave the rest
@@ -1088,7 +1103,7 @@ void ARMFrameLowering::emitPopInst(MachineBasicBlock &MBB,
if (Regs.empty())
continue;
- std::sort(Regs.begin(), Regs.end(), [&](unsigned LHS, unsigned RHS) {
+ llvm::sort(Regs.begin(), Regs.end(), [&](unsigned LHS, unsigned RHS) {
return TRI.getEncodingValue(LHS) < TRI.getEncodingValue(RHS);
});
@@ -1605,6 +1620,17 @@ void ARMFrameLowering::determineCalleeSaves(MachineFunction &MF,
(MFI.hasVarSizedObjects() || RegInfo->needsStackRealignment(MF)))
SavedRegs.set(ARM::R4);
+ // If a stack probe will be emitted, spill R4 and LR, since they are
+ // clobbered by the stack probe call.
+ // This estimate should be a safe, conservative estimate. The actual
+ // stack probe is enabled based on the size of the local objects;
+ // this estimate also includes the varargs store size.
+ if (STI.isTargetWindows() &&
+ WindowsRequiresStackProbe(MF, MFI.estimateStackSize(MF))) {
+ SavedRegs.set(ARM::R4);
+ SavedRegs.set(ARM::LR);
+ }
+
if (AFI->isThumb1OnlyFunction()) {
// Spill LR if Thumb1 function uses variable length argument lists.
if (AFI->getArgRegsSaveSize() > 0)
@@ -1797,34 +1823,36 @@ void ARMFrameLowering::determineCalleeSaves(MachineFunction &MF,
for (unsigned Reg : {ARM::R0, ARM::R1, ARM::R2, ARM::R3}) {
if (!MF.getRegInfo().isLiveIn(Reg)) {
--EntryRegDeficit;
- DEBUG(dbgs() << printReg(Reg, TRI)
- << " is unused argument register, EntryRegDeficit = "
- << EntryRegDeficit << "\n");
+ LLVM_DEBUG(dbgs()
+ << printReg(Reg, TRI)
+ << " is unused argument register, EntryRegDeficit = "
+ << EntryRegDeficit << "\n");
}
}
// Unused return registers can be clobbered in the epilogue for free.
int ExitRegDeficit = AFI->getReturnRegsCount() - 4;
- DEBUG(dbgs() << AFI->getReturnRegsCount()
- << " return regs used, ExitRegDeficit = " << ExitRegDeficit
- << "\n");
+ LLVM_DEBUG(dbgs() << AFI->getReturnRegsCount()
+ << " return regs used, ExitRegDeficit = "
+ << ExitRegDeficit << "\n");
int RegDeficit = std::max(EntryRegDeficit, ExitRegDeficit);
- DEBUG(dbgs() << "RegDeficit = " << RegDeficit << "\n");
+ LLVM_DEBUG(dbgs() << "RegDeficit = " << RegDeficit << "\n");
// r4-r6 can be used in the prologue if they are pushed by the first push
// instruction.
for (unsigned Reg : {ARM::R4, ARM::R5, ARM::R6}) {
if (SavedRegs.test(Reg)) {
--RegDeficit;
- DEBUG(dbgs() << printReg(Reg, TRI)
- << " is saved low register, RegDeficit = " << RegDeficit
- << "\n");
+ LLVM_DEBUG(dbgs() << printReg(Reg, TRI)
+ << " is saved low register, RegDeficit = "
+ << RegDeficit << "\n");
} else {
AvailableRegs.push_back(Reg);
- DEBUG(dbgs()
- << printReg(Reg, TRI)
- << " is non-saved low register, adding to AvailableRegs\n");
+ LLVM_DEBUG(
+ dbgs()
+ << printReg(Reg, TRI)
+ << " is non-saved low register, adding to AvailableRegs\n");
}
}
@@ -1832,12 +1860,13 @@ void ARMFrameLowering::determineCalleeSaves(MachineFunction &MF,
if (!HasFP) {
if (SavedRegs.test(ARM::R7)) {
--RegDeficit;
- DEBUG(dbgs() << "%r7 is saved low register, RegDeficit = "
- << RegDeficit << "\n");
+ LLVM_DEBUG(dbgs() << "%r7 is saved low register, RegDeficit = "
+ << RegDeficit << "\n");
} else {
AvailableRegs.push_back(ARM::R7);
- DEBUG(dbgs()
- << "%r7 is non-saved low register, adding to AvailableRegs\n");
+ LLVM_DEBUG(
+ dbgs()
+ << "%r7 is non-saved low register, adding to AvailableRegs\n");
}
}
@@ -1845,9 +1874,9 @@ void ARMFrameLowering::determineCalleeSaves(MachineFunction &MF,
for (unsigned Reg : {ARM::R8, ARM::R9, ARM::R10, ARM::R11}) {
if (SavedRegs.test(Reg)) {
++RegDeficit;
- DEBUG(dbgs() << printReg(Reg, TRI)
- << " is saved high register, RegDeficit = " << RegDeficit
- << "\n");
+ LLVM_DEBUG(dbgs() << printReg(Reg, TRI)
+ << " is saved high register, RegDeficit = "
+ << RegDeficit << "\n");
}
}
@@ -1859,11 +1888,11 @@ void ARMFrameLowering::determineCalleeSaves(MachineFunction &MF,
MF.getFrameInfo().isReturnAddressTaken())) {
if (SavedRegs.test(ARM::LR)) {
--RegDeficit;
- DEBUG(dbgs() << "%lr is saved register, RegDeficit = " << RegDeficit
- << "\n");
+ LLVM_DEBUG(dbgs() << "%lr is saved register, RegDeficit = "
+ << RegDeficit << "\n");
} else {
AvailableRegs.push_back(ARM::LR);
- DEBUG(dbgs() << "%lr is not saved, adding to AvailableRegs\n");
+ LLVM_DEBUG(dbgs() << "%lr is not saved, adding to AvailableRegs\n");
}
}
@@ -1872,11 +1901,11 @@ void ARMFrameLowering::determineCalleeSaves(MachineFunction &MF,
// instructions. This might not reduce RegDeficit all the way to zero,
// because we can only guarantee that r4-r6 are available, but r8-r11 may
// need saving.
- DEBUG(dbgs() << "Final RegDeficit = " << RegDeficit << "\n");
+ LLVM_DEBUG(dbgs() << "Final RegDeficit = " << RegDeficit << "\n");
for (; RegDeficit > 0 && !AvailableRegs.empty(); --RegDeficit) {
unsigned Reg = AvailableRegs.pop_back_val();
- DEBUG(dbgs() << "Spilling " << printReg(Reg, TRI)
- << " to make up reg deficit\n");
+ LLVM_DEBUG(dbgs() << "Spilling " << printReg(Reg, TRI)
+ << " to make up reg deficit\n");
SavedRegs.set(Reg);
NumGPRSpills++;
CS1Spilled = true;
@@ -1887,7 +1916,8 @@ void ARMFrameLowering::determineCalleeSaves(MachineFunction &MF,
if (Reg == ARM::LR)
LRSpilled = true;
}
- DEBUG(dbgs() << "After adding spills, RegDeficit = " << RegDeficit << "\n");
+ LLVM_DEBUG(dbgs() << "After adding spills, RegDeficit = " << RegDeficit
+ << "\n");
}
// If LR is not spilled, but at least one of R4, R5, R6, and R7 is spilled.
@@ -1908,7 +1938,7 @@ void ARMFrameLowering::determineCalleeSaves(MachineFunction &MF,
// If stack and double are 8-byte aligned and we are spilling an odd number
// of GPRs, spill one extra callee save GPR so we won't have to pad between
// the integer and double callee save areas.
- DEBUG(dbgs() << "NumGPRSpills = " << NumGPRSpills << "\n");
+ LLVM_DEBUG(dbgs() << "NumGPRSpills = " << NumGPRSpills << "\n");
unsigned TargetAlign = getStackAlignment();
if (TargetAlign >= 8 && (NumGPRSpills & 1)) {
if (CS1Spilled && !UnspilledCS1GPRs.empty()) {
@@ -1920,8 +1950,8 @@ void ARMFrameLowering::determineCalleeSaves(MachineFunction &MF,
(STI.isTargetWindows() && Reg == ARM::R11) ||
isARMLowRegister(Reg) || Reg == ARM::LR) {
SavedRegs.set(Reg);
- DEBUG(dbgs() << "Spilling " << printReg(Reg, TRI)
- << " to make up alignment\n");
+ LLVM_DEBUG(dbgs() << "Spilling " << printReg(Reg, TRI)
+ << " to make up alignment\n");
if (!MRI.isReserved(Reg) && !MRI.isPhysRegUsed(Reg))
ExtraCSSpill = true;
break;
@@ -1930,8 +1960,8 @@ void ARMFrameLowering::determineCalleeSaves(MachineFunction &MF,
} else if (!UnspilledCS2GPRs.empty() && !AFI->isThumb1OnlyFunction()) {
unsigned Reg = UnspilledCS2GPRs.front();
SavedRegs.set(Reg);
- DEBUG(dbgs() << "Spilling " << printReg(Reg, TRI)
- << " to make up alignment\n");
+ LLVM_DEBUG(dbgs() << "Spilling " << printReg(Reg, TRI)
+ << " to make up alignment\n");
if (!MRI.isReserved(Reg) && !MRI.isPhysRegUsed(Reg))
ExtraCSSpill = true;
}
@@ -2118,8 +2148,10 @@ void ARMFrameLowering::adjustForSegmentedStacks(
uint64_t StackSize = MFI.getStackSize();
- // Do not generate a prologue for functions with a stack of size zero
- if (StackSize == 0)
+ // Do not generate a prologue for leaf functions with a stack of size zero.
+ // For non-leaf functions we have to allow for the possibility that the
+ // call is to a non-split function, as in PR37807.
+ if (StackSize == 0 && !MFI.hasTailCall())
return;
// Use R4 and R5 as scratch registers.
diff --git a/lib/Target/ARM/ARMFrameLowering.h b/lib/Target/ARM/ARMFrameLowering.h
index 1f18e2bf80c4..e994cab28fe7 100644
--- a/lib/Target/ARM/ARMFrameLowering.h
+++ b/lib/Target/ARM/ARMFrameLowering.h
@@ -44,6 +44,8 @@ public:
bool noFramePointerElim(const MachineFunction &MF) const override;
+ bool enableCalleeSaveSkip(const MachineFunction &MF) const override;
+
bool hasFP(const MachineFunction &MF) const override;
bool hasReservedCallFrame(const MachineFunction &MF) const override;
bool canSimplifyCallFramePseudos(const MachineFunction &MF) const override;
diff --git a/lib/Target/ARM/ARMHazardRecognizer.cpp b/lib/Target/ARM/ARMHazardRecognizer.cpp
index f878bf9937a4..d5dacbe08770 100644
--- a/lib/Target/ARM/ARMHazardRecognizer.cpp
+++ b/lib/Target/ARM/ARMHazardRecognizer.cpp
@@ -37,7 +37,7 @@ ARMHazardRecognizer::getHazardType(SUnit *SU, int Stalls) {
MachineInstr *MI = SU->getInstr();
- if (!MI->isDebugValue()) {
+ if (!MI->isDebugInstr()) {
// Look for special VMLA / VMLS hazards. A VMUL / VADD / VSUB following
// a VMLA / VMLS will cause 4 cycle stall.
const MCInstrDesc &MCID = MI->getDesc();
@@ -81,7 +81,7 @@ void ARMHazardRecognizer::Reset() {
void ARMHazardRecognizer::EmitInstruction(SUnit *SU) {
MachineInstr *MI = SU->getInstr();
- if (!MI->isDebugValue()) {
+ if (!MI->isDebugInstr()) {
LastMI = MI;
FpMLxStalls = 0;
}
diff --git a/lib/Target/ARM/ARMISelDAGToDAG.cpp b/lib/Target/ARM/ARMISelDAGToDAG.cpp
index 8d32510e2004..081d4ff033bd 100644
--- a/lib/Target/ARM/ARMISelDAGToDAG.cpp
+++ b/lib/Target/ARM/ARMISelDAGToDAG.cpp
@@ -97,6 +97,8 @@ public:
return SelectImmShifterOperand(N, A, B, false);
}
+ bool SelectAddLikeOr(SDNode *Parent, SDValue N, SDValue &Out);
+
bool SelectAddrModeImm12(SDValue N, SDValue &Base, SDValue &OffImm);
bool SelectLdStSOReg(SDValue N, SDValue &Base, SDValue &Offset, SDValue &Opc);
@@ -118,8 +120,10 @@ public:
SDValue &Offset, SDValue &Opc);
bool SelectAddrMode3Offset(SDNode *Op, SDValue N,
SDValue &Offset, SDValue &Opc);
- bool SelectAddrMode5(SDValue N, SDValue &Base,
- SDValue &Offset);
+ bool IsAddressingMode5(SDValue N, SDValue &Base, SDValue &Offset,
+ int Lwb, int Upb, bool FP16);
+ bool SelectAddrMode5(SDValue N, SDValue &Base, SDValue &Offset);
+ bool SelectAddrMode5FP16(SDValue N, SDValue &Base, SDValue &Offset);
bool SelectAddrMode6(SDNode *Parent, SDValue N, SDValue &Addr,SDValue &Align);
bool SelectAddrMode6Offset(SDNode *Op, SDValue N, SDValue &Offset);
@@ -199,10 +203,11 @@ private:
/// SelectVLDDup - Select NEON load-duplicate intrinsics. NumVecs
/// should be 1, 2, 3 or 4. The opcode array specifies the instructions used
- /// for loading D registers. (Q registers are not supported.)
- void SelectVLDDup(SDNode *N, bool isUpdating, unsigned NumVecs,
- const uint16_t *DOpcodes,
- const uint16_t *QOpcodes = nullptr);
+ /// for loading D registers.
+ void SelectVLDDup(SDNode *N, bool IsIntrinsic, bool isUpdating,
+ unsigned NumVecs, const uint16_t *DOpcodes,
+ const uint16_t *QOpcodes0 = nullptr,
+ const uint16_t *QOpcodes1 = nullptr);
/// Try to select SBFX/UBFX instructions for ARM.
bool tryV6T2BitfieldExtractOp(SDNode *N, bool isSigned);
@@ -281,7 +286,7 @@ static bool isOpcWithIntImmediate(SDNode *N, unsigned Opc, unsigned& Imm) {
isInt32Immediate(N->getOperand(1).getNode(), Imm);
}
-/// \brief Check whether a particular node is a constant value representable as
+/// Check whether a particular node is a constant value representable as
/// (N * Scale) where (N in [\p RangeMin, \p RangeMax).
///
/// \param ScaledConstant [out] - On success, the pre-scaled constant value.
@@ -498,7 +503,7 @@ bool ARMDAGToDAGISel::canExtractShiftFromMul(const SDValue &N,
void ARMDAGToDAGISel::replaceDAGValue(const SDValue &N, SDValue M) {
CurDAG->RepositionNode(N.getNode()->getIterator(), M.getNode());
- CurDAG->ReplaceAllUsesWith(N, M);
+ ReplaceUses(N, M);
}
bool ARMDAGToDAGISel::SelectImmShifterOperand(SDValue N,
@@ -567,6 +572,14 @@ bool ARMDAGToDAGISel::SelectRegShifterOperand(SDValue N,
return true;
}
+// Determine whether an ISD::OR's operands are suitable to turn the operation
+// into an addition, which often has more compact encodings.
+bool ARMDAGToDAGISel::SelectAddLikeOr(SDNode *Parent, SDValue N, SDValue &Out) {
+ assert(Parent->getOpcode() == ISD::OR && "unexpected parent");
+ Out = N;
+ return CurDAG->haveNoCommonBitsSet(N, Parent->getOperand(1));
+}
+
bool ARMDAGToDAGISel::SelectAddrModeImm12(SDValue N,
SDValue &Base,
@@ -886,8 +899,8 @@ bool ARMDAGToDAGISel::SelectAddrMode3Offset(SDNode *Op, SDValue N,
return true;
}
-bool ARMDAGToDAGISel::SelectAddrMode5(SDValue N,
- SDValue &Base, SDValue &Offset) {
+bool ARMDAGToDAGISel::IsAddressingMode5(SDValue N, SDValue &Base, SDValue &Offset,
+ int Lwb, int Upb, bool FP16) {
if (!CurDAG->isBaseWithConstantOffset(N)) {
Base = N;
if (N.getOpcode() == ISD::FrameIndex) {
@@ -907,8 +920,9 @@ bool ARMDAGToDAGISel::SelectAddrMode5(SDValue N,
// If the RHS is +/- imm8, fold into addr mode.
int RHSC;
- if (isScaledConstantInRange(N.getOperand(1), /*Scale=*/4,
- -256 + 1, 256, RHSC)) {
+ const int Scale = FP16 ? 2 : 4;
+
+ if (isScaledConstantInRange(N.getOperand(1), Scale, Lwb, Upb, RHSC)) {
Base = N.getOperand(0);
if (Base.getOpcode() == ISD::FrameIndex) {
int FI = cast<FrameIndexSDNode>(Base)->getIndex();
@@ -921,17 +935,43 @@ bool ARMDAGToDAGISel::SelectAddrMode5(SDValue N,
AddSub = ARM_AM::sub;
RHSC = -RHSC;
}
- Offset = CurDAG->getTargetConstant(ARM_AM::getAM5Opc(AddSub, RHSC),
- SDLoc(N), MVT::i32);
+
+ if (FP16)
+ Offset = CurDAG->getTargetConstant(ARM_AM::getAM5FP16Opc(AddSub, RHSC),
+ SDLoc(N), MVT::i32);
+ else
+ Offset = CurDAG->getTargetConstant(ARM_AM::getAM5Opc(AddSub, RHSC),
+ SDLoc(N), MVT::i32);
+
return true;
}
Base = N;
- Offset = CurDAG->getTargetConstant(ARM_AM::getAM5Opc(ARM_AM::add, 0),
- SDLoc(N), MVT::i32);
+
+ if (FP16)
+ Offset = CurDAG->getTargetConstant(ARM_AM::getAM5FP16Opc(ARM_AM::add, 0),
+ SDLoc(N), MVT::i32);
+ else
+ Offset = CurDAG->getTargetConstant(ARM_AM::getAM5Opc(ARM_AM::add, 0),
+ SDLoc(N), MVT::i32);
+
return true;
}
+bool ARMDAGToDAGISel::SelectAddrMode5(SDValue N,
+ SDValue &Base, SDValue &Offset) {
+ int Lwb = -256 + 1;
+ int Upb = 256;
+ return IsAddressingMode5(N, Base, Offset, Lwb, Upb, /*FP16=*/ false);
+}
+
+bool ARMDAGToDAGISel::SelectAddrMode5FP16(SDValue N,
+ SDValue &Base, SDValue &Offset) {
+ int Lwb = -512 + 1;
+ int Upb = 512;
+ return IsAddressingMode5(N, Base, Offset, Lwb, Upb, /*FP16=*/ true);
+}
+
bool ARMDAGToDAGISel::SelectAddrMode6(SDNode *Parent, SDValue N, SDValue &Addr,
SDValue &Align) {
Addr = N;
@@ -1467,7 +1507,7 @@ bool ARMDAGToDAGISel::tryT2IndexedLoad(SDNode *N) {
return false;
}
-/// \brief Form a GPRPair pseudo register from a pair of GPR regs.
+/// Form a GPRPair pseudo register from a pair of GPR regs.
SDNode *ARMDAGToDAGISel::createGPRPairNode(EVT VT, SDValue V0, SDValue V1) {
SDLoc dl(V0.getNode());
SDValue RegClass =
@@ -1478,7 +1518,7 @@ SDNode *ARMDAGToDAGISel::createGPRPairNode(EVT VT, SDValue V0, SDValue V1) {
return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops);
}
-/// \brief Form a D register from a pair of S registers.
+/// Form a D register from a pair of S registers.
SDNode *ARMDAGToDAGISel::createSRegPairNode(EVT VT, SDValue V0, SDValue V1) {
SDLoc dl(V0.getNode());
SDValue RegClass =
@@ -1489,7 +1529,7 @@ SDNode *ARMDAGToDAGISel::createSRegPairNode(EVT VT, SDValue V0, SDValue V1) {
return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops);
}
-/// \brief Form a quad register from a pair of D registers.
+/// Form a quad register from a pair of D registers.
SDNode *ARMDAGToDAGISel::createDRegPairNode(EVT VT, SDValue V0, SDValue V1) {
SDLoc dl(V0.getNode());
SDValue RegClass = CurDAG->getTargetConstant(ARM::QPRRegClassID, dl,
@@ -1500,7 +1540,7 @@ SDNode *ARMDAGToDAGISel::createDRegPairNode(EVT VT, SDValue V0, SDValue V1) {
return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops);
}
-/// \brief Form 4 consecutive D registers from a pair of Q registers.
+/// Form 4 consecutive D registers from a pair of Q registers.
SDNode *ARMDAGToDAGISel::createQRegPairNode(EVT VT, SDValue V0, SDValue V1) {
SDLoc dl(V0.getNode());
SDValue RegClass = CurDAG->getTargetConstant(ARM::QQPRRegClassID, dl,
@@ -1511,7 +1551,7 @@ SDNode *ARMDAGToDAGISel::createQRegPairNode(EVT VT, SDValue V0, SDValue V1) {
return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops);
}
-/// \brief Form 4 consecutive S registers.
+/// Form 4 consecutive S registers.
SDNode *ARMDAGToDAGISel::createQuadSRegsNode(EVT VT, SDValue V0, SDValue V1,
SDValue V2, SDValue V3) {
SDLoc dl(V0.getNode());
@@ -1526,7 +1566,7 @@ SDNode *ARMDAGToDAGISel::createQuadSRegsNode(EVT VT, SDValue V0, SDValue V1,
return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops);
}
-/// \brief Form 4 consecutive D registers.
+/// Form 4 consecutive D registers.
SDNode *ARMDAGToDAGISel::createQuadDRegsNode(EVT VT, SDValue V0, SDValue V1,
SDValue V2, SDValue V3) {
SDLoc dl(V0.getNode());
@@ -1541,7 +1581,7 @@ SDNode *ARMDAGToDAGISel::createQuadDRegsNode(EVT VT, SDValue V0, SDValue V1,
return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops);
}
-/// \brief Form 4 consecutive Q registers.
+/// Form 4 consecutive Q registers.
SDNode *ARMDAGToDAGISel::createQuadQRegsNode(EVT VT, SDValue V0, SDValue V1,
SDValue V2, SDValue V3) {
SDLoc dl(V0.getNode());
@@ -1708,7 +1748,9 @@ void ARMDAGToDAGISel::SelectVLD(SDNode *N, bool isUpdating, unsigned NumVecs,
SDLoc dl(N);
SDValue MemAddr, Align;
- unsigned AddrOpIdx = isUpdating ? 1 : 2;
+ bool IsIntrinsic = !isUpdating; // By coincidence, all supported updating
+ // nodes are not intrinsics.
+ unsigned AddrOpIdx = IsIntrinsic ? 2 : 1;
if (!SelectAddrMode6(N, N->getOperand(AddrOpIdx), MemAddr, Align))
return;
@@ -1732,9 +1774,7 @@ void ARMDAGToDAGISel::SelectVLD(SDNode *N, bool isUpdating, unsigned NumVecs,
case MVT::v4f32:
case MVT::v4i32: OpcodeIndex = 2; break;
case MVT::v2f64:
- case MVT::v2i64: OpcodeIndex = 3;
- assert(NumVecs == 1 && "v2i64 type only supported for VLD1");
- break;
+ case MVT::v2i64: OpcodeIndex = 3; break;
}
EVT ResTy;
@@ -1765,15 +1805,17 @@ void ARMDAGToDAGISel::SelectVLD(SDNode *N, bool isUpdating, unsigned NumVecs,
Ops.push_back(Align);
if (isUpdating) {
SDValue Inc = N->getOperand(AddrOpIdx + 1);
- // FIXME: VLD1/VLD2 fixed increment doesn't need Reg0. Remove the reg0
- // case entirely when the rest are updated to that form, too.
bool IsImmUpdate = isPerfectIncrement(Inc, VT, NumVecs);
- if ((NumVecs <= 2) && !IsImmUpdate)
- Opc = getVLDSTRegisterUpdateOpcode(Opc);
- // FIXME: We use a VLD1 for v1i64 even if the pseudo says vld2/3/4, so
- // check for that explicitly too. Horribly hacky, but temporary.
- if ((NumVecs > 2 && !isVLDfixed(Opc)) || !IsImmUpdate)
- Ops.push_back(IsImmUpdate ? Reg0 : Inc);
+ if (!IsImmUpdate) {
+ // We use a VLD1 for v1i64 even if the pseudo says vld2/3/4, so
+ // check for the opcode rather than the number of vector elements.
+ if (isVLDfixed(Opc))
+ Opc = getVLDSTRegisterUpdateOpcode(Opc);
+ Ops.push_back(Inc);
+ // VLD1/VLD2 fixed increment does not need Reg0 so only include it in
+ // the operands if not such an opcode.
+ } else if (!isVLDfixed(Opc))
+ Ops.push_back(Reg0);
}
Ops.push_back(Pred);
Ops.push_back(Reg0);
@@ -1844,7 +1886,9 @@ void ARMDAGToDAGISel::SelectVST(SDNode *N, bool isUpdating, unsigned NumVecs,
SDLoc dl(N);
SDValue MemAddr, Align;
- unsigned AddrOpIdx = isUpdating ? 1 : 2;
+ bool IsIntrinsic = !isUpdating; // By coincidence, all supported updating
+ // nodes are not intrinsics.
+ unsigned AddrOpIdx = IsIntrinsic ? 2 : 1;
unsigned Vec0Idx = 3; // AddrOpIdx + (isUpdating ? 2 : 1)
if (!SelectAddrMode6(N, N->getOperand(AddrOpIdx), MemAddr, Align))
return;
@@ -1862,19 +1906,19 @@ void ARMDAGToDAGISel::SelectVST(SDNode *N, bool isUpdating, unsigned NumVecs,
default: llvm_unreachable("unhandled vst type");
// Double-register operations:
case MVT::v8i8: OpcodeIndex = 0; break;
+ case MVT::v4f16:
case MVT::v4i16: OpcodeIndex = 1; break;
case MVT::v2f32:
case MVT::v2i32: OpcodeIndex = 2; break;
case MVT::v1i64: OpcodeIndex = 3; break;
// Quad-register operations:
case MVT::v16i8: OpcodeIndex = 0; break;
+ case MVT::v8f16:
case MVT::v8i16: OpcodeIndex = 1; break;
case MVT::v4f32:
case MVT::v4i32: OpcodeIndex = 2; break;
case MVT::v2f64:
- case MVT::v2i64: OpcodeIndex = 3;
- assert(NumVecs == 1 && "v2i64 type only supported for VST1");
- break;
+ case MVT::v2i64: OpcodeIndex = 3; break;
}
std::vector<EVT> ResTys;
@@ -1919,16 +1963,17 @@ void ARMDAGToDAGISel::SelectVST(SDNode *N, bool isUpdating, unsigned NumVecs,
Ops.push_back(Align);
if (isUpdating) {
SDValue Inc = N->getOperand(AddrOpIdx + 1);
- // FIXME: VST1/VST2 fixed increment doesn't need Reg0. Remove the reg0
- // case entirely when the rest are updated to that form, too.
bool IsImmUpdate = isPerfectIncrement(Inc, VT, NumVecs);
- if (NumVecs <= 2 && !IsImmUpdate)
- Opc = getVLDSTRegisterUpdateOpcode(Opc);
- // FIXME: We use a VST1 for v1i64 even if the pseudo says vld2/3/4, so
- // check for that explicitly too. Horribly hacky, but temporary.
- if (!IsImmUpdate)
+ if (!IsImmUpdate) {
+ // We use a VST1 for v1i64 even if the pseudo says VST2/3/4, so
+ // check for the opcode rather than the number of vector elements.
+ if (isVSTfixed(Opc))
+ Opc = getVLDSTRegisterUpdateOpcode(Opc);
Ops.push_back(Inc);
- else if (NumVecs > 2 && !isVSTfixed(Opc))
+ }
+ // VST1/VST2 fixed increment does not need Reg0 so only include it in
+ // the operands if not such an opcode.
+ else if (!isVSTfixed(Opc))
Ops.push_back(Reg0);
}
Ops.push_back(SrcReg);
@@ -1993,7 +2038,9 @@ void ARMDAGToDAGISel::SelectVLDSTLane(SDNode *N, bool IsLoad, bool isUpdating,
SDLoc dl(N);
SDValue MemAddr, Align;
- unsigned AddrOpIdx = isUpdating ? 1 : 2;
+ bool IsIntrinsic = !isUpdating; // By coincidence, all supported updating
+ // nodes are not intrinsics.
+ unsigned AddrOpIdx = IsIntrinsic ? 2 : 1;
unsigned Vec0Idx = 3; // AddrOpIdx + (isUpdating ? 2 : 1)
if (!SelectAddrMode6(N, N->getOperand(AddrOpIdx), MemAddr, Align))
return;
@@ -2109,21 +2156,22 @@ void ARMDAGToDAGISel::SelectVLDSTLane(SDNode *N, bool IsLoad, bool isUpdating,
CurDAG->RemoveDeadNode(N);
}
-void ARMDAGToDAGISel::SelectVLDDup(SDNode *N, bool isUpdating, unsigned NumVecs,
+void ARMDAGToDAGISel::SelectVLDDup(SDNode *N, bool IsIntrinsic,
+ bool isUpdating, unsigned NumVecs,
const uint16_t *DOpcodes,
- const uint16_t *QOpcodes) {
+ const uint16_t *QOpcodes0,
+ const uint16_t *QOpcodes1) {
assert(NumVecs >= 1 && NumVecs <= 4 && "VLDDup NumVecs out-of-range");
SDLoc dl(N);
SDValue MemAddr, Align;
- if (!SelectAddrMode6(N, N->getOperand(1), MemAddr, Align))
+ unsigned AddrOpIdx = IsIntrinsic ? 2 : 1;
+ if (!SelectAddrMode6(N, N->getOperand(AddrOpIdx), MemAddr, Align))
return;
- MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
- MemOp[0] = cast<MemIntrinsicSDNode>(N)->getMemOperand();
-
SDValue Chain = N->getOperand(0);
EVT VT = N->getValueType(0);
+ bool is64BitVector = VT.is64BitVector();
unsigned Alignment = 0;
if (NumVecs != 3) {
@@ -2140,49 +2188,84 @@ void ARMDAGToDAGISel::SelectVLDDup(SDNode *N, bool isUpdating, unsigned NumVecs,
}
Align = CurDAG->getTargetConstant(Alignment, dl, MVT::i32);
- unsigned Opc;
+ unsigned OpcodeIndex;
switch (VT.getSimpleVT().SimpleTy) {
default: llvm_unreachable("unhandled vld-dup type");
- case MVT::v8i8: Opc = DOpcodes[0]; break;
- case MVT::v16i8: Opc = QOpcodes[0]; break;
- case MVT::v4i16: Opc = DOpcodes[1]; break;
- case MVT::v8i16: Opc = QOpcodes[1]; break;
+ case MVT::v8i8:
+ case MVT::v16i8: OpcodeIndex = 0; break;
+ case MVT::v4i16:
+ case MVT::v8i16: OpcodeIndex = 1; break;
case MVT::v2f32:
- case MVT::v2i32: Opc = DOpcodes[2]; break;
+ case MVT::v2i32:
case MVT::v4f32:
- case MVT::v4i32: Opc = QOpcodes[2]; break;
- }
-
- SDValue Pred = getAL(CurDAG, dl);
- SDValue Reg0 = CurDAG->getRegister(0, MVT::i32);
- SmallVector<SDValue, 6> Ops;
- Ops.push_back(MemAddr);
- Ops.push_back(Align);
- if (isUpdating) {
- // fixed-stride update instructions don't have an explicit writeback
- // operand. It's implicit in the opcode itself.
- SDValue Inc = N->getOperand(2);
- bool IsImmUpdate =
- isPerfectIncrement(Inc, VT.getVectorElementType(), NumVecs);
- if (NumVecs <= 2 && !IsImmUpdate)
- Opc = getVLDSTRegisterUpdateOpcode(Opc);
- if (!IsImmUpdate)
- Ops.push_back(Inc);
- // FIXME: VLD3 and VLD4 haven't been updated to that form yet.
- else if (NumVecs > 2)
- Ops.push_back(Reg0);
+ case MVT::v4i32: OpcodeIndex = 2; break;
+ case MVT::v1f64:
+ case MVT::v1i64: OpcodeIndex = 3; break;
}
- Ops.push_back(Pred);
- Ops.push_back(Reg0);
- Ops.push_back(Chain);
unsigned ResTyElts = (NumVecs == 3) ? 4 : NumVecs;
+ if (!is64BitVector)
+ ResTyElts *= 2;
+ EVT ResTy = EVT::getVectorVT(*CurDAG->getContext(), MVT::i64, ResTyElts);
+
std::vector<EVT> ResTys;
- ResTys.push_back(EVT::getVectorVT(*CurDAG->getContext(), MVT::i64,ResTyElts));
+ ResTys.push_back(ResTy);
if (isUpdating)
ResTys.push_back(MVT::i32);
ResTys.push_back(MVT::Other);
- SDNode *VLdDup = CurDAG->getMachineNode(Opc, dl, ResTys, Ops);
+
+ SDValue Pred = getAL(CurDAG, dl);
+ SDValue Reg0 = CurDAG->getRegister(0, MVT::i32);
+
+ SDNode *VLdDup;
+ if (is64BitVector || NumVecs == 1) {
+ SmallVector<SDValue, 6> Ops;
+ Ops.push_back(MemAddr);
+ Ops.push_back(Align);
+ unsigned Opc = is64BitVector ? DOpcodes[OpcodeIndex] :
+ QOpcodes0[OpcodeIndex];
+ if (isUpdating) {
+ // fixed-stride update instructions don't have an explicit writeback
+ // operand. It's implicit in the opcode itself.
+ SDValue Inc = N->getOperand(2);
+ bool IsImmUpdate =
+ isPerfectIncrement(Inc, VT.getVectorElementType(), NumVecs);
+ if (NumVecs <= 2 && !IsImmUpdate)
+ Opc = getVLDSTRegisterUpdateOpcode(Opc);
+ if (!IsImmUpdate)
+ Ops.push_back(Inc);
+ // FIXME: VLD3 and VLD4 haven't been updated to that form yet.
+ else if (NumVecs > 2)
+ Ops.push_back(Reg0);
+ }
+ Ops.push_back(Pred);
+ Ops.push_back(Reg0);
+ Ops.push_back(Chain);
+ VLdDup = CurDAG->getMachineNode(Opc, dl, ResTys, Ops);
+ } else if (NumVecs == 2) {
+ const SDValue OpsA[] = { MemAddr, Align, Pred, Reg0, Chain };
+ SDNode *VLdA = CurDAG->getMachineNode(QOpcodes0[OpcodeIndex],
+ dl, ResTys, OpsA);
+
+ Chain = SDValue(VLdA, 1);
+ const SDValue OpsB[] = { MemAddr, Align, Pred, Reg0, Chain };
+ VLdDup = CurDAG->getMachineNode(QOpcodes1[OpcodeIndex], dl, ResTys, OpsB);
+ } else {
+ SDValue ImplDef =
+ SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, dl, ResTy), 0);
+ const SDValue OpsA[] = { MemAddr, Align, ImplDef, Pred, Reg0, Chain };
+ SDNode *VLdA = CurDAG->getMachineNode(QOpcodes0[OpcodeIndex],
+ dl, ResTys, OpsA);
+
+ SDValue SuperReg = SDValue(VLdA, 0);
+ Chain = SDValue(VLdA, 1);
+ const SDValue OpsB[] = { MemAddr, Align, SuperReg, Pred, Reg0, Chain };
+ VLdDup = CurDAG->getMachineNode(QOpcodes1[OpcodeIndex], dl, ResTys, OpsB);
+ }
+
+ // Transfer memoperands.
+ MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
+ MemOp[0] = cast<MemIntrinsicSDNode>(N)->getMemOperand();
cast<MachineSDNode>(VLdDup)->setMemRefs(MemOp, MemOp + 1);
// Extract the subregisters.
@@ -2191,10 +2274,11 @@ void ARMDAGToDAGISel::SelectVLDDup(SDNode *N, bool isUpdating, unsigned NumVecs,
} else {
SDValue SuperReg = SDValue(VLdDup, 0);
static_assert(ARM::dsub_7 == ARM::dsub_0 + 7, "Unexpected subreg numbering");
- unsigned SubIdx = ARM::dsub_0;
- for (unsigned Vec = 0; Vec < NumVecs; ++Vec)
+ unsigned SubIdx = is64BitVector ? ARM::dsub_0 : ARM::qsub_0;
+ for (unsigned Vec = 0; Vec != NumVecs; ++Vec) {
ReplaceUses(SDValue(N, Vec),
CurDAG->getTargetExtractSubreg(SubIdx+Vec, dl, VT, SuperReg));
+ }
}
ReplaceUses(SDValue(N, NumVecs), SDValue(VLdDup, 1));
if (isUpdating)
@@ -2253,6 +2337,7 @@ bool ARMDAGToDAGISel::tryV6T2BitfieldExtractOp(SDNode *N, bool isSigned) {
return true;
}
+ assert(LSB + Width + 1 <= 32 && "Shouldn't create an invalid ubfx");
SDValue Ops[] = { N->getOperand(0).getOperand(0),
CurDAG->getTargetConstant(LSB, dl, MVT::i32),
CurDAG->getTargetConstant(Width, dl, MVT::i32),
@@ -2277,6 +2362,7 @@ bool ARMDAGToDAGISel::tryV6T2BitfieldExtractOp(SDNode *N, bool isSigned) {
if (LSB < 0)
return false;
SDValue Reg0 = CurDAG->getRegister(0, MVT::i32);
+ assert(LSB + Width + 1 <= 32 && "Shouldn't create an invalid ubfx");
SDValue Ops[] = { N->getOperand(0).getOperand(0),
CurDAG->getTargetConstant(LSB, dl, MVT::i32),
CurDAG->getTargetConstant(Width, dl, MVT::i32),
@@ -2298,6 +2384,7 @@ bool ARMDAGToDAGISel::tryV6T2BitfieldExtractOp(SDNode *N, bool isSigned) {
// Note: The width operand is encoded as width-1.
unsigned Width = MSB - LSB;
SDValue Reg0 = CurDAG->getRegister(0, MVT::i32);
+ assert(Srl_imm + Width + 1 <= 32 && "Shouldn't create an invalid ubfx");
SDValue Ops[] = { N->getOperand(0).getOperand(0),
CurDAG->getTargetConstant(Srl_imm, dl, MVT::i32),
CurDAG->getTargetConstant(Width, dl, MVT::i32),
@@ -2318,6 +2405,7 @@ bool ARMDAGToDAGISel::tryV6T2BitfieldExtractOp(SDNode *N, bool isSigned) {
return false;
SDValue Reg0 = CurDAG->getRegister(0, MVT::i32);
+ assert(LSB + Width <= 32 && "Shouldn't create an invalid ubfx");
SDValue Ops[] = { N->getOperand(0).getOperand(0),
CurDAG->getTargetConstant(LSB, dl, MVT::i32),
CurDAG->getTargetConstant(Width - 1, dl, MVT::i32),
@@ -2427,7 +2515,7 @@ void ARMDAGToDAGISel::SelectCMPZ(SDNode *N, bool &SwitchEQNEToPLMI) {
SDValue X = And.getOperand(0);
auto C = dyn_cast<ConstantSDNode>(And.getOperand(1));
- if (!C || !X->hasOneUse())
+ if (!C)
return;
auto Range = getContiguousRangeOfSetBits(C->getAPIntValue());
if (!Range)
@@ -2765,7 +2853,7 @@ void ARMDAGToDAGISel::Select(SDNode *N) {
}
}
case ARMISD::SUBE: {
- if (!Subtarget->hasV6Ops())
+ if (!Subtarget->hasV6Ops() || !Subtarget->hasDSP())
break;
// Look for a pattern to match SMMLS
// (sube a, (smul_loHi a, b), (subc 0, (smul_LOhi(a, b))))
@@ -3026,14 +3114,14 @@ void ARMDAGToDAGISel::Select(SDNode *N) {
ARM::VLD1DUPd32 };
static const uint16_t QOpcodes[] = { ARM::VLD1DUPq8, ARM::VLD1DUPq16,
ARM::VLD1DUPq32 };
- SelectVLDDup(N, false, 1, DOpcodes, QOpcodes);
+ SelectVLDDup(N, /* IsIntrinsic= */ false, false, 1, DOpcodes, QOpcodes);
return;
}
case ARMISD::VLD2DUP: {
static const uint16_t Opcodes[] = { ARM::VLD2DUPd8, ARM::VLD2DUPd16,
ARM::VLD2DUPd32 };
- SelectVLDDup(N, false, 2, Opcodes);
+ SelectVLDDup(N, /* IsIntrinsic= */ false, false, 2, Opcodes);
return;
}
@@ -3041,7 +3129,7 @@ void ARMDAGToDAGISel::Select(SDNode *N) {
static const uint16_t Opcodes[] = { ARM::VLD3DUPd8Pseudo,
ARM::VLD3DUPd16Pseudo,
ARM::VLD3DUPd32Pseudo };
- SelectVLDDup(N, false, 3, Opcodes);
+ SelectVLDDup(N, /* IsIntrinsic= */ false, false, 3, Opcodes);
return;
}
@@ -3049,7 +3137,7 @@ void ARMDAGToDAGISel::Select(SDNode *N) {
static const uint16_t Opcodes[] = { ARM::VLD4DUPd8Pseudo,
ARM::VLD4DUPd16Pseudo,
ARM::VLD4DUPd32Pseudo };
- SelectVLDDup(N, false, 4, Opcodes);
+ SelectVLDDup(N, /* IsIntrinsic= */ false, false, 4, Opcodes);
return;
}
@@ -3060,7 +3148,7 @@ void ARMDAGToDAGISel::Select(SDNode *N) {
static const uint16_t QOpcodes[] = { ARM::VLD1DUPq8wb_fixed,
ARM::VLD1DUPq16wb_fixed,
ARM::VLD1DUPq32wb_fixed };
- SelectVLDDup(N, true, 1, DOpcodes, QOpcodes);
+ SelectVLDDup(N, /* IsIntrinsic= */ false, true, 1, DOpcodes, QOpcodes);
return;
}
@@ -3068,7 +3156,7 @@ void ARMDAGToDAGISel::Select(SDNode *N) {
static const uint16_t Opcodes[] = { ARM::VLD2DUPd8wb_fixed,
ARM::VLD2DUPd16wb_fixed,
ARM::VLD2DUPd32wb_fixed };
- SelectVLDDup(N, true, 2, Opcodes);
+ SelectVLDDup(N, /* IsIntrinsic= */ false, true, 2, Opcodes);
return;
}
@@ -3076,7 +3164,7 @@ void ARMDAGToDAGISel::Select(SDNode *N) {
static const uint16_t Opcodes[] = { ARM::VLD3DUPd8Pseudo_UPD,
ARM::VLD3DUPd16Pseudo_UPD,
ARM::VLD3DUPd32Pseudo_UPD };
- SelectVLDDup(N, true, 3, Opcodes);
+ SelectVLDDup(N, /* IsIntrinsic= */ false, true, 3, Opcodes);
return;
}
@@ -3084,7 +3172,7 @@ void ARMDAGToDAGISel::Select(SDNode *N) {
static const uint16_t Opcodes[] = { ARM::VLD4DUPd8Pseudo_UPD,
ARM::VLD4DUPd16Pseudo_UPD,
ARM::VLD4DUPd32Pseudo_UPD };
- SelectVLDDup(N, true, 4, Opcodes);
+ SelectVLDDup(N, /* IsIntrinsic= */ false, true, 4, Opcodes);
return;
}
@@ -3407,6 +3495,51 @@ void ARMDAGToDAGISel::Select(SDNode *N) {
return;
}
+ case Intrinsic::arm_neon_vld1x2: {
+ static const uint16_t DOpcodes[] = { ARM::VLD1q8, ARM::VLD1q16,
+ ARM::VLD1q32, ARM::VLD1q64 };
+ static const uint16_t QOpcodes[] = { ARM::VLD1d8QPseudo,
+ ARM::VLD1d16QPseudo,
+ ARM::VLD1d32QPseudo,
+ ARM::VLD1d64QPseudo };
+ SelectVLD(N, false, 2, DOpcodes, QOpcodes, nullptr);
+ return;
+ }
+
+ case Intrinsic::arm_neon_vld1x3: {
+ static const uint16_t DOpcodes[] = { ARM::VLD1d8TPseudo,
+ ARM::VLD1d16TPseudo,
+ ARM::VLD1d32TPseudo,
+ ARM::VLD1d64TPseudo };
+ static const uint16_t QOpcodes0[] = { ARM::VLD1q8LowTPseudo_UPD,
+ ARM::VLD1q16LowTPseudo_UPD,
+ ARM::VLD1q32LowTPseudo_UPD,
+ ARM::VLD1q64LowTPseudo_UPD };
+ static const uint16_t QOpcodes1[] = { ARM::VLD1q8HighTPseudo,
+ ARM::VLD1q16HighTPseudo,
+ ARM::VLD1q32HighTPseudo,
+ ARM::VLD1q64HighTPseudo };
+ SelectVLD(N, false, 3, DOpcodes, QOpcodes0, QOpcodes1);
+ return;
+ }
+
+ case Intrinsic::arm_neon_vld1x4: {
+ static const uint16_t DOpcodes[] = { ARM::VLD1d8QPseudo,
+ ARM::VLD1d16QPseudo,
+ ARM::VLD1d32QPseudo,
+ ARM::VLD1d64QPseudo };
+ static const uint16_t QOpcodes0[] = { ARM::VLD1q8LowQPseudo_UPD,
+ ARM::VLD1q16LowQPseudo_UPD,
+ ARM::VLD1q32LowQPseudo_UPD,
+ ARM::VLD1q64LowQPseudo_UPD };
+ static const uint16_t QOpcodes1[] = { ARM::VLD1q8HighQPseudo,
+ ARM::VLD1q16HighQPseudo,
+ ARM::VLD1q32HighQPseudo,
+ ARM::VLD1q64HighQPseudo };
+ SelectVLD(N, false, 4, DOpcodes, QOpcodes0, QOpcodes1);
+ return;
+ }
+
case Intrinsic::arm_neon_vld2: {
static const uint16_t DOpcodes[] = { ARM::VLD2d8, ARM::VLD2d16,
ARM::VLD2d32, ARM::VLD1q64 };
@@ -3446,6 +3579,52 @@ void ARMDAGToDAGISel::Select(SDNode *N) {
return;
}
+ case Intrinsic::arm_neon_vld2dup: {
+ static const uint16_t DOpcodes[] = { ARM::VLD2DUPd8, ARM::VLD2DUPd16,
+ ARM::VLD2DUPd32, ARM::VLD1q64 };
+ static const uint16_t QOpcodes0[] = { ARM::VLD2DUPq8EvenPseudo,
+ ARM::VLD2DUPq16EvenPseudo,
+ ARM::VLD2DUPq32EvenPseudo };
+ static const uint16_t QOpcodes1[] = { ARM::VLD2DUPq8OddPseudo,
+ ARM::VLD2DUPq16OddPseudo,
+ ARM::VLD2DUPq32OddPseudo };
+ SelectVLDDup(N, /* IsIntrinsic= */ true, false, 2,
+ DOpcodes, QOpcodes0, QOpcodes1);
+ return;
+ }
+
+ case Intrinsic::arm_neon_vld3dup: {
+ static const uint16_t DOpcodes[] = { ARM::VLD3DUPd8Pseudo,
+ ARM::VLD3DUPd16Pseudo,
+ ARM::VLD3DUPd32Pseudo,
+ ARM::VLD1d64TPseudo };
+ static const uint16_t QOpcodes0[] = { ARM::VLD3DUPq8EvenPseudo,
+ ARM::VLD3DUPq16EvenPseudo,
+ ARM::VLD3DUPq32EvenPseudo };
+ static const uint16_t QOpcodes1[] = { ARM::VLD3DUPq8OddPseudo,
+ ARM::VLD3DUPq16OddPseudo,
+ ARM::VLD3DUPq32OddPseudo };
+ SelectVLDDup(N, /* IsIntrinsic= */ true, false, 3,
+ DOpcodes, QOpcodes0, QOpcodes1);
+ return;
+ }
+
+ case Intrinsic::arm_neon_vld4dup: {
+ static const uint16_t DOpcodes[] = { ARM::VLD4DUPd8Pseudo,
+ ARM::VLD4DUPd16Pseudo,
+ ARM::VLD4DUPd32Pseudo,
+ ARM::VLD1d64QPseudo };
+ static const uint16_t QOpcodes0[] = { ARM::VLD4DUPq8EvenPseudo,
+ ARM::VLD4DUPq16EvenPseudo,
+ ARM::VLD4DUPq32EvenPseudo };
+ static const uint16_t QOpcodes1[] = { ARM::VLD4DUPq8OddPseudo,
+ ARM::VLD4DUPq16OddPseudo,
+ ARM::VLD4DUPq32OddPseudo };
+ SelectVLDDup(N, /* IsIntrinsic= */ true, false, 4,
+ DOpcodes, QOpcodes0, QOpcodes1);
+ return;
+ }
+
case Intrinsic::arm_neon_vld2lane: {
static const uint16_t DOpcodes[] = { ARM::VLD2LNd8Pseudo,
ARM::VLD2LNd16Pseudo,
@@ -3485,6 +3664,51 @@ void ARMDAGToDAGISel::Select(SDNode *N) {
return;
}
+ case Intrinsic::arm_neon_vst1x2: {
+ static const uint16_t DOpcodes[] = { ARM::VST1q8, ARM::VST1q16,
+ ARM::VST1q32, ARM::VST1q64 };
+ static const uint16_t QOpcodes[] = { ARM::VST1d8QPseudo,
+ ARM::VST1d16QPseudo,
+ ARM::VST1d32QPseudo,
+ ARM::VST1d64QPseudo };
+ SelectVST(N, false, 2, DOpcodes, QOpcodes, nullptr);
+ return;
+ }
+
+ case Intrinsic::arm_neon_vst1x3: {
+ static const uint16_t DOpcodes[] = { ARM::VST1d8TPseudo,
+ ARM::VST1d16TPseudo,
+ ARM::VST1d32TPseudo,
+ ARM::VST1d64TPseudo };
+ static const uint16_t QOpcodes0[] = { ARM::VST1q8LowTPseudo_UPD,
+ ARM::VST1q16LowTPseudo_UPD,
+ ARM::VST1q32LowTPseudo_UPD,
+ ARM::VST1q64LowTPseudo_UPD };
+ static const uint16_t QOpcodes1[] = { ARM::VST1q8HighTPseudo,
+ ARM::VST1q16HighTPseudo,
+ ARM::VST1q32HighTPseudo,
+ ARM::VST1q64HighTPseudo };
+ SelectVST(N, false, 3, DOpcodes, QOpcodes0, QOpcodes1);
+ return;
+ }
+
+ case Intrinsic::arm_neon_vst1x4: {
+ static const uint16_t DOpcodes[] = { ARM::VST1d8QPseudo,
+ ARM::VST1d16QPseudo,
+ ARM::VST1d32QPseudo,
+ ARM::VST1d64QPseudo };
+ static const uint16_t QOpcodes0[] = { ARM::VST1q8LowQPseudo_UPD,
+ ARM::VST1q16LowQPseudo_UPD,
+ ARM::VST1q32LowQPseudo_UPD,
+ ARM::VST1q64LowQPseudo_UPD };
+ static const uint16_t QOpcodes1[] = { ARM::VST1q8HighQPseudo,
+ ARM::VST1q16HighQPseudo,
+ ARM::VST1q32HighQPseudo,
+ ARM::VST1q64HighQPseudo };
+ SelectVST(N, false, 4, DOpcodes, QOpcodes0, QOpcodes1);
+ return;
+ }
+
case Intrinsic::arm_neon_vst2: {
static const uint16_t DOpcodes[] = { ARM::VST2d8, ARM::VST2d16,
ARM::VST2d32, ARM::VST1q64 };
diff --git a/lib/Target/ARM/ARMISelLowering.cpp b/lib/Target/ARM/ARMISelLowering.cpp
index aeda7c06a27a..47222a66f798 100644
--- a/lib/Target/ARM/ARMISelLowering.cpp
+++ b/lib/Target/ARM/ARMISelLowering.cpp
@@ -53,7 +53,6 @@
#include "llvm/CodeGen/MachineMemOperand.h"
#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
-#include "llvm/CodeGen/MachineValueType.h"
#include "llvm/CodeGen/RuntimeLibcalls.h"
#include "llvm/CodeGen/SelectionDAG.h"
#include "llvm/CodeGen/SelectionDAGNodes.h"
@@ -97,6 +96,7 @@
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/KnownBits.h"
+#include "llvm/Support/MachineValueType.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetMachine.h"
@@ -308,13 +308,6 @@ ARMTargetLowering::ARMTargetLowering(const TargetMachine &TM,
setCmpLibcallCC(LC.Op, LC.Cond);
}
}
-
- // Set the correct calling convention for ARMv7k WatchOS. It's just
- // AAPCS_VFP for functions as simple as libcalls.
- if (Subtarget->isTargetWatchABI()) {
- for (int i = 0; i < RTLIB::UNKNOWN_LIBCALL; ++i)
- setLibcallCallingConv((RTLIB::Libcall)i, CallingConv::ARM_AAPCS_VFP);
- }
}
// These libcalls are not available in 32-bit.
@@ -522,6 +515,16 @@ ARMTargetLowering::ARMTargetLowering(const TargetMachine &TM,
addRegisterClass(MVT::f64, &ARM::DPRRegClass);
}
+ if (Subtarget->hasFullFP16()) {
+ addRegisterClass(MVT::f16, &ARM::HPRRegClass);
+ setOperationAction(ISD::BITCAST, MVT::i16, Custom);
+ setOperationAction(ISD::BITCAST, MVT::i32, Custom);
+ setOperationAction(ISD::BITCAST, MVT::f16, Custom);
+
+ setOperationAction(ISD::FMINNUM, MVT::f16, Legal);
+ setOperationAction(ISD::FMAXNUM, MVT::f16, Legal);
+ }
+
for (MVT VT : MVT::vector_valuetypes()) {
for (MVT InnerVT : MVT::vector_valuetypes()) {
setTruncStoreAction(VT, InnerVT, Expand);
@@ -558,6 +561,11 @@ ARMTargetLowering::ARMTargetLowering(const TargetMachine &TM,
addQRTypeForNEON(MVT::v4i32);
addQRTypeForNEON(MVT::v2i64);
+ if (Subtarget->hasFullFP16()) {
+ addQRTypeForNEON(MVT::v8f16);
+ addDRTypeForNEON(MVT::v4f16);
+ }
+
// v2f64 is legal so that QR subregs can be extracted as f64 elements, but
// neither Neon nor VFP support any arithmetic operations on it.
// The same with v4f32. But keep in mind that vadd, vsub, vmul are natively
@@ -820,10 +828,12 @@ ARMTargetLowering::ARMTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::SRA, MVT::i64, Custom);
setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::i64, Custom);
- setOperationAction(ISD::ADDC, MVT::i32, Custom);
- setOperationAction(ISD::ADDE, MVT::i32, Custom);
- setOperationAction(ISD::SUBC, MVT::i32, Custom);
- setOperationAction(ISD::SUBE, MVT::i32, Custom);
+ // Expand to __aeabi_l{lsl,lsr,asr} calls for Thumb1.
+ if (Subtarget->isThumb1Only()) {
+ setOperationAction(ISD::SHL_PARTS, MVT::i32, Expand);
+ setOperationAction(ISD::SRA_PARTS, MVT::i32, Expand);
+ setOperationAction(ISD::SRL_PARTS, MVT::i32, Expand);
+ }
if (!Subtarget->isThumb1Only() && Subtarget->hasV6T2Ops())
setOperationAction(ISD::BITREVERSE, MVT::i32, Legal);
@@ -949,7 +959,7 @@ ARMTargetLowering::ARMTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::STACKSAVE, MVT::Other, Expand);
setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand);
- if (Subtarget->getTargetTriple().isWindowsItaniumEnvironment())
+ if (Subtarget->isTargetWindows())
setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32, Custom);
else
setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32, Expand);
@@ -1036,13 +1046,18 @@ ARMTargetLowering::ARMTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::SELECT_CC, MVT::i32, Custom);
setOperationAction(ISD::SELECT_CC, MVT::f32, Custom);
setOperationAction(ISD::SELECT_CC, MVT::f64, Custom);
+ if (Subtarget->hasFullFP16()) {
+ setOperationAction(ISD::SETCC, MVT::f16, Expand);
+ setOperationAction(ISD::SELECT, MVT::f16, Custom);
+ setOperationAction(ISD::SELECT_CC, MVT::f16, Custom);
+ }
- // Thumb-1 cannot currently select ARMISD::SUBE.
- if (!Subtarget->isThumb1Only())
- setOperationAction(ISD::SETCCE, MVT::i32, Custom);
+ setOperationAction(ISD::SETCCCARRY, MVT::i32, Custom);
setOperationAction(ISD::BRCOND, MVT::Other, Custom);
setOperationAction(ISD::BR_CC, MVT::i32, Custom);
+ if (Subtarget->hasFullFP16())
+ setOperationAction(ISD::BR_CC, MVT::f16, Custom);
setOperationAction(ISD::BR_CC, MVT::f32, Custom);
setOperationAction(ISD::BR_CC, MVT::f64, Custom);
setOperationAction(ISD::BR_JT, MVT::Other, Custom);
@@ -1121,6 +1136,8 @@ ARMTargetLowering::ARMTargetLowering(const TargetMachine &TM,
if (Subtarget->hasNEON()) {
// vmin and vmax aren't available in a scalar form, so we use
// a NEON instruction with an undef lane instead.
+ setOperationAction(ISD::FMINNAN, MVT::f16, Legal);
+ setOperationAction(ISD::FMAXNAN, MVT::f16, Legal);
setOperationAction(ISD::FMINNAN, MVT::f32, Legal);
setOperationAction(ISD::FMAXNAN, MVT::f32, Legal);
setOperationAction(ISD::FMINNAN, MVT::v2f32, Legal);
@@ -1259,6 +1276,9 @@ const char *ARMTargetLowering::getTargetNodeName(unsigned Opcode) const {
case ARMISD::VMOVRRD: return "ARMISD::VMOVRRD";
case ARMISD::VMOVDRR: return "ARMISD::VMOVDRR";
+ case ARMISD::VMOVhr: return "ARMISD::VMOVhr";
+ case ARMISD::VMOVrh: return "ARMISD::VMOVrh";
+ case ARMISD::VMOVSR: return "ARMISD::VMOVSR";
case ARMISD::EH_SJLJ_SETJMP: return "ARMISD::EH_SJLJ_SETJMP";
case ARMISD::EH_SJLJ_LONGJMP: return "ARMISD::EH_SJLJ_LONGJMP";
@@ -1337,6 +1357,8 @@ const char *ARMTargetLowering::getTargetNodeName(unsigned Opcode) const {
case ARMISD::SMLALDX: return "ARMISD::SMLALDX";
case ARMISD::SMLSLD: return "ARMISD::SMLSLD";
case ARMISD::SMLSLDX: return "ARMISD::SMLSLDX";
+ case ARMISD::SMMLAR: return "ARMISD::SMMLAR";
+ case ARMISD::SMMLSR: return "ARMISD::SMMLSR";
case ARMISD::BUILD_VECTOR: return "ARMISD::BUILD_VECTOR";
case ARMISD::BFI: return "ARMISD::BFI";
case ARMISD::VORRIMM: return "ARMISD::VORRIMM";
@@ -2465,12 +2487,37 @@ ARMTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
assert(VA.isRegLoc() && "Can only return in registers!");
SDValue Arg = OutVals[realRVLocIdx];
+ bool ReturnF16 = false;
+
+ if (Subtarget->hasFullFP16() && Subtarget->isTargetHardFloat()) {
+ // Half-precision return values can be returned like this:
+ //
+ // t11 f16 = fadd ...
+ // t12: i16 = bitcast t11
+ // t13: i32 = zero_extend t12
+ // t14: f32 = bitcast t13 <~~~~~~~ Arg
+ //
+ // to avoid code generation for bitcasts, we simply set Arg to the node
+ // that produces the f16 value, t11 in this case.
+ //
+ if (Arg.getValueType() == MVT::f32 && Arg.getOpcode() == ISD::BITCAST) {
+ SDValue ZE = Arg.getOperand(0);
+ if (ZE.getOpcode() == ISD::ZERO_EXTEND && ZE.getValueType() == MVT::i32) {
+ SDValue BC = ZE.getOperand(0);
+ if (BC.getOpcode() == ISD::BITCAST && BC.getValueType() == MVT::i16) {
+ Arg = BC.getOperand(0);
+ ReturnF16 = true;
+ }
+ }
+ }
+ }
switch (VA.getLocInfo()) {
default: llvm_unreachable("Unknown loc info!");
case CCValAssign::Full: break;
case CCValAssign::BCvt:
- Arg = DAG.getNode(ISD::BITCAST, dl, VA.getLocVT(), Arg);
+ if (!ReturnF16)
+ Arg = DAG.getNode(ISD::BITCAST, dl, VA.getLocVT(), Arg);
break;
}
@@ -2518,7 +2565,8 @@ ARMTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
// Guarantee that all emitted copies are
// stuck together, avoiding something bad.
Flag = Chain.getValue(1);
- RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT()));
+ RetOps.push_back(DAG.getRegister(VA.getLocReg(),
+ ReturnF16 ? MVT::f16 : VA.getLocVT()));
}
const ARMBaseRegisterInfo *TRI = Subtarget->getRegisterInfo();
const MCPhysReg *I =
@@ -2738,7 +2786,7 @@ SDValue ARMTargetLowering::LowerBlockAddress(SDValue Op,
return DAG.getNode(ARMISD::PIC_ADD, DL, PtrVT, Result, PICLabel);
}
-/// \brief Convert a TLS address reference into the correct sequence of loads
+/// Convert a TLS address reference into the correct sequence of loads
/// and calls to compute the variable's address for Darwin, and return an
/// SDValue containing the final node.
@@ -2959,7 +3007,7 @@ ARMTargetLowering::LowerToTLSExecModels(GlobalAddressSDNode *GA,
SDValue
ARMTargetLowering::LowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const {
GlobalAddressSDNode *GA = cast<GlobalAddressSDNode>(Op);
- if (DAG.getTarget().Options.EmulatedTLS)
+ if (DAG.getTarget().useEmulatedTLS())
return LowerToTLSEmulatedModel(GA, DAG);
if (Subtarget->isTargetDarwin())
@@ -3675,11 +3723,14 @@ SDValue ARMTargetLowering::LowerFormalArguments(
} else {
const TargetRegisterClass *RC;
- if (RegVT == MVT::f32)
+
+ if (RegVT == MVT::f16)
+ RC = &ARM::HPRRegClass;
+ else if (RegVT == MVT::f32)
RC = &ARM::SPRRegClass;
- else if (RegVT == MVT::f64)
+ else if (RegVT == MVT::f64 || RegVT == MVT::v4f16)
RC = &ARM::DPRRegClass;
- else if (RegVT == MVT::v2f64)
+ else if (RegVT == MVT::v2f64 || RegVT == MVT::v8f16)
RC = &ARM::QPRRegClass;
else if (RegVT == MVT::i32)
RC = AFI->isThumb1OnlyFunction() ? &ARM::tGPRRegClass
@@ -3799,8 +3850,8 @@ SDValue ARMTargetLowering::getARMCmp(SDValue LHS, SDValue RHS, ISD::CondCode CC,
const SDLoc &dl) const {
if (ConstantSDNode *RHSC = dyn_cast<ConstantSDNode>(RHS.getNode())) {
unsigned C = RHSC->getZExtValue();
- if (!isLegalICmpImmediate(C)) {
- // Constant does not fit, try adjusting it by one?
+ if (!isLegalICmpImmediate((int32_t)C)) {
+ // Constant does not fit, try adjusting it by one.
switch (CC) {
default: break;
case ISD::SETLT:
@@ -3940,6 +3991,29 @@ ARMTargetLowering::getARMXALUOOp(SDValue Op, SelectionDAG &DAG,
Value = DAG.getNode(ISD::SUB, dl, Op.getValueType(), LHS, RHS);
OverflowCmp = DAG.getNode(ARMISD::CMP, dl, MVT::Glue, LHS, RHS);
break;
+ case ISD::UMULO:
+ // We generate a UMUL_LOHI and then check if the high word is 0.
+ ARMcc = DAG.getConstant(ARMCC::EQ, dl, MVT::i32);
+ Value = DAG.getNode(ISD::UMUL_LOHI, dl,
+ DAG.getVTList(Op.getValueType(), Op.getValueType()),
+ LHS, RHS);
+ OverflowCmp = DAG.getNode(ARMISD::CMP, dl, MVT::Glue, Value.getValue(1),
+ DAG.getConstant(0, dl, MVT::i32));
+ Value = Value.getValue(0); // We only want the low 32 bits for the result.
+ break;
+ case ISD::SMULO:
+ // We generate a SMUL_LOHI and then check if all the bits of the high word
+ // are the same as the sign bit of the low word.
+ ARMcc = DAG.getConstant(ARMCC::EQ, dl, MVT::i32);
+ Value = DAG.getNode(ISD::SMUL_LOHI, dl,
+ DAG.getVTList(Op.getValueType(), Op.getValueType()),
+ LHS, RHS);
+ OverflowCmp = DAG.getNode(ARMISD::CMP, dl, MVT::Glue, Value.getValue(1),
+ DAG.getNode(ISD::SRA, dl, Op.getValueType(),
+ Value.getValue(0),
+ DAG.getConstant(31, dl, MVT::i32)));
+ Value = Value.getValue(0); // We only want the low 32 bits for the result.
+ break;
} // switch (...)
return std::make_pair(Value, OverflowCmp);
@@ -3973,11 +4047,12 @@ static SDValue ConvertBooleanCarryToCarryFlag(SDValue BoolCarry,
SDLoc DL(BoolCarry);
EVT CarryVT = BoolCarry.getValueType();
- APInt NegOne = APInt::getAllOnesValue(CarryVT.getScalarSizeInBits());
// This converts the boolean value carry into the carry flag by doing
- // ARMISD::ADDC Carry, ~0
- return DAG.getNode(ARMISD::ADDC, DL, DAG.getVTList(CarryVT, MVT::i32),
- BoolCarry, DAG.getConstant(NegOne, DL, CarryVT));
+ // ARMISD::SUBC Carry, 1
+ SDValue Carry = DAG.getNode(ARMISD::SUBC, DL,
+ DAG.getVTList(CarryVT, MVT::i32),
+ BoolCarry, DAG.getConstant(1, DL, CarryVT));
+ return Carry.getValue(1);
}
static SDValue ConvertCarryFlagToBooleanCarry(SDValue Flags, EVT VT,
@@ -4313,6 +4388,48 @@ static bool isSaturatingConditional(const SDValue &Op, SDValue &V,
return false;
}
+// Check if a condition of the type x < k ? k : x can be converted into a
+// bit operation instead of conditional moves.
+// Currently this is allowed given:
+// - The conditions and values match up
+// - k is 0 or -1 (all ones)
+// This function will not check the last condition, thats up to the caller
+// It returns true if the transformation can be made, and in such case
+// returns x in V, and k in SatK.
+static bool isLowerSaturatingConditional(const SDValue &Op, SDValue &V,
+ SDValue &SatK)
+{
+ SDValue LHS = Op.getOperand(0);
+ SDValue RHS = Op.getOperand(1);
+ ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(4))->get();
+ SDValue TrueVal = Op.getOperand(2);
+ SDValue FalseVal = Op.getOperand(3);
+
+ SDValue *K = isa<ConstantSDNode>(LHS) ? &LHS : isa<ConstantSDNode>(RHS)
+ ? &RHS
+ : nullptr;
+
+ // No constant operation in comparison, early out
+ if (!K)
+ return false;
+
+ SDValue KTmp = isa<ConstantSDNode>(TrueVal) ? TrueVal : FalseVal;
+ V = (KTmp == TrueVal) ? FalseVal : TrueVal;
+ SDValue VTmp = (K && *K == LHS) ? RHS : LHS;
+
+ // If the constant on left and right side, or variable on left and right,
+ // does not match, early out
+ if (*K != KTmp || V != VTmp)
+ return false;
+
+ if (isLowerSaturate(LHS, RHS, TrueVal, FalseVal, CC, *K)) {
+ SatK = *K;
+ return true;
+ }
+
+ return false;
+}
+
SDValue ARMTargetLowering::LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const {
EVT VT = Op.getValueType();
SDLoc dl(Op);
@@ -4331,6 +4448,25 @@ SDValue ARMTargetLowering::LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const {
DAG.getConstant(countTrailingOnes(SatConstant), dl, VT));
}
+ // Try to convert expressions of the form x < k ? k : x (and similar forms)
+ // into more efficient bit operations, which is possible when k is 0 or -1
+ // On ARM and Thumb-2 which have flexible operand 2 this will result in
+ // single instructions. On Thumb the shift and the bit operation will be two
+ // instructions.
+ // Only allow this transformation on full-width (32-bit) operations
+ SDValue LowerSatConstant;
+ if (VT == MVT::i32 &&
+ isLowerSaturatingConditional(Op, SatValue, LowerSatConstant)) {
+ SDValue ShiftV = DAG.getNode(ISD::SRA, dl, VT, SatValue,
+ DAG.getConstant(31, dl, VT));
+ if (isNullConstant(LowerSatConstant)) {
+ SDValue NotShiftV = DAG.getNode(ISD::XOR, dl, VT, ShiftV,
+ DAG.getAllOnesConstant(dl, VT));
+ return DAG.getNode(ISD::AND, dl, VT, SatValue, NotShiftV);
+ } else if (isAllOnesConstant(LowerSatConstant))
+ return DAG.getNode(ISD::OR, dl, VT, SatValue, ShiftV);
+ }
+
SDValue LHS = Op.getOperand(0);
SDValue RHS = Op.getOperand(1);
ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(4))->get();
@@ -4380,9 +4516,12 @@ SDValue ARMTargetLowering::LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const {
bool InvalidOnQNaN;
FPCCToARMCC(CC, CondCode, CondCode2, InvalidOnQNaN);
- // Try to generate VMAXNM/VMINNM on ARMv8.
- if (Subtarget->hasFPARMv8() && (TrueVal.getValueType() == MVT::f32 ||
- TrueVal.getValueType() == MVT::f64)) {
+ // Normalize the fp compare. If RHS is zero we keep it there so we match
+ // CMPFPw0 instead of CMPFP.
+ if (Subtarget->hasFPARMv8() && !isFloatingPointZero(RHS) &&
+ (TrueVal.getValueType() == MVT::f16 ||
+ TrueVal.getValueType() == MVT::f32 ||
+ TrueVal.getValueType() == MVT::f64)) {
bool swpCmpOps = false;
bool swpVselOps = false;
checkVSELConstraints(CC, CondCode, swpCmpOps, swpVselOps);
@@ -4532,10 +4671,14 @@ SDValue ARMTargetLowering::LowerBRCOND(SDValue Op, SelectionDAG &DAG) const {
SDValue Dest = Op.getOperand(2);
SDLoc dl(Op);
- // Optimize {s|u}{add|sub}.with.overflow feeding into a branch instruction.
+ // Optimize {s|u}{add|sub|mul}.with.overflow feeding into a branch
+ // instruction.
unsigned Opc = Cond.getOpcode();
- if (Cond.getResNo() == 1 && (Opc == ISD::SADDO || Opc == ISD::UADDO ||
- Opc == ISD::SSUBO || Opc == ISD::USUBO)) {
+ bool OptimizeMul = (Opc == ISD::SMULO || Opc == ISD::UMULO) &&
+ !Subtarget->isThumb1Only();
+ if (Cond.getResNo() == 1 &&
+ (Opc == ISD::SADDO || Opc == ISD::UADDO || Opc == ISD::SSUBO ||
+ Opc == ISD::USUBO || OptimizeMul)) {
// Only lower legal XALUO ops.
if (!DAG.getTargetLoweringInfo().isTypeLegal(Cond->getValueType(0)))
return SDValue();
@@ -4579,11 +4722,15 @@ SDValue ARMTargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) const {
}
}
- // Optimize {s|u}{add|sub}.with.overflow feeding into a branch instruction.
+ // Optimize {s|u}{add|sub|mul}.with.overflow feeding into a branch
+ // instruction.
unsigned Opc = LHS.getOpcode();
+ bool OptimizeMul = (Opc == ISD::SMULO || Opc == ISD::UMULO) &&
+ !Subtarget->isThumb1Only();
if (LHS.getResNo() == 1 && (isOneConstant(RHS) || isNullConstant(RHS)) &&
(Opc == ISD::SADDO || Opc == ISD::UADDO || Opc == ISD::SSUBO ||
- Opc == ISD::USUBO) && (CC == ISD::SETEQ || CC == ISD::SETNE)) {
+ Opc == ISD::USUBO || OptimizeMul) &&
+ (CC == ISD::SETEQ || CC == ISD::SETNE)) {
// Only lower legal XALUO ops.
if (!DAG.getTargetLoweringInfo().isTypeLegal(LHS->getValueType(0)))
return SDValue();
@@ -4614,8 +4761,6 @@ SDValue ARMTargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) const {
Chain, Dest, ARMcc, CCR, Cmp);
}
- assert(LHS.getValueType() == MVT::f32 || LHS.getValueType() == MVT::f64);
-
if (getTargetMachine().Options.UnsafeFPMath &&
(CC == ISD::SETEQ || CC == ISD::SETOEQ ||
CC == ISD::SETNE || CC == ISD::SETUNE)) {
@@ -4979,7 +5124,8 @@ static SDValue CombineVMOVDRRCandidateWithVecOp(const SDNode *BC,
/// use a VMOVDRR or VMOVRRD node. This should not be done when the non-i64
/// operand type is illegal (e.g., v2f32 for a target that doesn't support
/// vectors), since the legalizer won't know what to do with that.
-static SDValue ExpandBITCAST(SDNode *N, SelectionDAG &DAG) {
+static SDValue ExpandBITCAST(SDNode *N, SelectionDAG &DAG,
+ const ARMSubtarget *Subtarget) {
const TargetLowering &TLI = DAG.getTargetLoweringInfo();
SDLoc dl(N);
SDValue Op = N->getOperand(0);
@@ -4988,8 +5134,78 @@ static SDValue ExpandBITCAST(SDNode *N, SelectionDAG &DAG) {
// source or destination of the bit convert.
EVT SrcVT = Op.getValueType();
EVT DstVT = N->getValueType(0);
- assert((SrcVT == MVT::i64 || DstVT == MVT::i64) &&
- "ExpandBITCAST called for non-i64 type");
+ const bool HasFullFP16 = Subtarget->hasFullFP16();
+
+ if (SrcVT == MVT::f32 && DstVT == MVT::i32) {
+ // FullFP16: half values are passed in S-registers, and we don't
+ // need any of the bitcast and moves:
+ //
+ // t2: f32,ch = CopyFromReg t0, Register:f32 %0
+ // t5: i32 = bitcast t2
+ // t18: f16 = ARMISD::VMOVhr t5
+ if (Op.getOpcode() != ISD::CopyFromReg ||
+ Op.getValueType() != MVT::f32)
+ return SDValue();
+
+ auto Move = N->use_begin();
+ if (Move->getOpcode() != ARMISD::VMOVhr)
+ return SDValue();
+
+ SDValue Ops[] = { Op.getOperand(0), Op.getOperand(1) };
+ SDValue Copy = DAG.getNode(ISD::CopyFromReg, SDLoc(Op), MVT::f16, Ops);
+ DAG.ReplaceAllUsesWith(*Move, &Copy);
+ return Copy;
+ }
+
+ if (SrcVT == MVT::i16 && DstVT == MVT::f16) {
+ if (!HasFullFP16)
+ return SDValue();
+ // SoftFP: read half-precision arguments:
+ //
+ // t2: i32,ch = ...
+ // t7: i16 = truncate t2 <~~~~ Op
+ // t8: f16 = bitcast t7 <~~~~ N
+ //
+ if (Op.getOperand(0).getValueType() == MVT::i32)
+ return DAG.getNode(ARMISD::VMOVhr, SDLoc(Op),
+ MVT::f16, Op.getOperand(0));
+
+ return SDValue();
+ }
+
+ // Half-precision return values
+ if (SrcVT == MVT::f16 && DstVT == MVT::i16) {
+ if (!HasFullFP16)
+ return SDValue();
+ //
+ // t11: f16 = fadd t8, t10
+ // t12: i16 = bitcast t11 <~~~ SDNode N
+ // t13: i32 = zero_extend t12
+ // t16: ch,glue = CopyToReg t0, Register:i32 %r0, t13
+ // t17: ch = ARMISD::RET_FLAG t16, Register:i32 %r0, t16:1
+ //
+ // transform this into:
+ //
+ // t20: i32 = ARMISD::VMOVrh t11
+ // t16: ch,glue = CopyToReg t0, Register:i32 %r0, t20
+ //
+ auto ZeroExtend = N->use_begin();
+ if (N->use_size() != 1 || ZeroExtend->getOpcode() != ISD::ZERO_EXTEND ||
+ ZeroExtend->getValueType(0) != MVT::i32)
+ return SDValue();
+
+ auto Copy = ZeroExtend->use_begin();
+ if (Copy->getOpcode() == ISD::CopyToReg &&
+ Copy->use_begin()->getOpcode() == ARMISD::RET_FLAG) {
+ SDValue Cvt = DAG.getNode(ARMISD::VMOVrh, SDLoc(Op), MVT::i32, Op);
+ DAG.ReplaceAllUsesWith(*ZeroExtend, &Cvt);
+ return Cvt;
+ }
+ return SDValue();
+ }
+
+ if (!(SrcVT == MVT::i64 || DstVT == MVT::i64))
+ return SDValue();
// Turn i64->f64 into VMOVDRR.
if (SrcVT == MVT::i64 && TLI.isTypeLegal(DstVT)) {
@@ -5566,16 +5782,22 @@ static SDValue LowerVSETCC(SDValue Op, SelectionDAG &DAG) {
return Result;
}
-static SDValue LowerSETCCE(SDValue Op, SelectionDAG &DAG) {
+static SDValue LowerSETCCCARRY(SDValue Op, SelectionDAG &DAG) {
SDValue LHS = Op.getOperand(0);
SDValue RHS = Op.getOperand(1);
SDValue Carry = Op.getOperand(2);
SDValue Cond = Op.getOperand(3);
SDLoc DL(Op);
- assert(LHS.getSimpleValueType().isInteger() && "SETCCE is integer only.");
+ assert(LHS.getSimpleValueType().isInteger() && "SETCCCARRY is integer only.");
+
+ // ARMISD::SUBE expects a carry not a borrow like ISD::SUBCARRY so we
+ // have to invert the carry first.
+ Carry = DAG.getNode(ISD::SUB, DL, MVT::i32,
+ DAG.getConstant(1, DL, MVT::i32), Carry);
+ // This converts the boolean value carry into the carry flag.
+ Carry = ConvertBooleanCarryToCarryFlag(Carry, DAG);
- assert(Carry.getOpcode() != ISD::CARRY_FALSE);
SDVTList VTs = DAG.getVTList(LHS.getValueType(), MVT::i32);
SDValue Cmp = DAG.getNode(ARMISD::SUBE, DL, VTs, LHS, RHS, Carry);
@@ -5731,23 +5953,34 @@ static SDValue isNEONModifiedImm(uint64_t SplatBits, uint64_t SplatUndef,
SDValue ARMTargetLowering::LowerConstantFP(SDValue Op, SelectionDAG &DAG,
const ARMSubtarget *ST) const {
- bool IsDouble = Op.getValueType() == MVT::f64;
+ EVT VT = Op.getValueType();
+ bool IsDouble = (VT == MVT::f64);
ConstantFPSDNode *CFP = cast<ConstantFPSDNode>(Op);
const APFloat &FPVal = CFP->getValueAPF();
// Prevent floating-point constants from using literal loads
// when execute-only is enabled.
if (ST->genExecuteOnly()) {
+ // If we can represent the constant as an immediate, don't lower it
+ if (isFPImmLegal(FPVal, VT))
+ return Op;
+ // Otherwise, construct as integer, and move to float register
APInt INTVal = FPVal.bitcastToAPInt();
SDLoc DL(CFP);
- if (IsDouble) {
- SDValue Lo = DAG.getConstant(INTVal.trunc(32), DL, MVT::i32);
- SDValue Hi = DAG.getConstant(INTVal.lshr(32).trunc(32), DL, MVT::i32);
- if (!ST->isLittle())
- std::swap(Lo, Hi);
- return DAG.getNode(ARMISD::VMOVDRR, DL, MVT::f64, Lo, Hi);
- } else {
- return DAG.getConstant(INTVal, DL, MVT::i32);
+ switch (VT.getSimpleVT().SimpleTy) {
+ default:
+ llvm_unreachable("Unknown floating point type!");
+ break;
+ case MVT::f64: {
+ SDValue Lo = DAG.getConstant(INTVal.trunc(32), DL, MVT::i32);
+ SDValue Hi = DAG.getConstant(INTVal.lshr(32).trunc(32), DL, MVT::i32);
+ if (!ST->isLittle())
+ std::swap(Lo, Hi);
+ return DAG.getNode(ARMISD::VMOVDRR, DL, MVT::f64, Lo, Hi);
+ }
+ case MVT::f32:
+ return DAG.getNode(ARMISD::VMOVSR, DL, VT,
+ DAG.getConstant(INTVal, DL, MVT::i32));
}
}
@@ -6598,10 +6831,9 @@ SDValue ARMTargetLowering::ReconstructShuffle(SDValue Op,
}
// Final sanity check before we try to actually produce a shuffle.
- DEBUG(
- for (auto Src : Sources)
- assert(Src.ShuffleVec.getValueType() == ShuffleVT);
- );
+ LLVM_DEBUG(for (auto Src
+ : Sources)
+ assert(Src.ShuffleVec.getValueType() == ShuffleVT););
// The stars all align, our next step is to produce the mask for the shuffle.
SmallVector<int, 8> Mask(ShuffleVT.getVectorNumElements(), -1);
@@ -7490,39 +7722,15 @@ static SDValue LowerUDIV(SDValue Op, SelectionDAG &DAG) {
return N0;
}
-static SDValue LowerADDC_ADDE_SUBC_SUBE(SDValue Op, SelectionDAG &DAG) {
- EVT VT = Op.getNode()->getValueType(0);
- SDVTList VTs = DAG.getVTList(VT, MVT::i32);
-
- unsigned Opc;
- bool ExtraOp = false;
- switch (Op.getOpcode()) {
- default: llvm_unreachable("Invalid code");
- case ISD::ADDC: Opc = ARMISD::ADDC; break;
- case ISD::ADDE: Opc = ARMISD::ADDE; ExtraOp = true; break;
- case ISD::SUBC: Opc = ARMISD::SUBC; break;
- case ISD::SUBE: Opc = ARMISD::SUBE; ExtraOp = true; break;
- }
-
- if (!ExtraOp)
- return DAG.getNode(Opc, SDLoc(Op), VTs, Op.getOperand(0),
- Op.getOperand(1));
- return DAG.getNode(Opc, SDLoc(Op), VTs, Op.getOperand(0),
- Op.getOperand(1), Op.getOperand(2));
-}
-
static SDValue LowerADDSUBCARRY(SDValue Op, SelectionDAG &DAG) {
SDNode *N = Op.getNode();
EVT VT = N->getValueType(0);
SDVTList VTs = DAG.getVTList(VT, MVT::i32);
SDValue Carry = Op.getOperand(2);
- EVT CarryVT = Carry.getValueType();
SDLoc DL(Op);
- APInt NegOne = APInt::getAllOnesValue(CarryVT.getScalarSizeInBits());
-
SDValue Result;
if (Op.getOpcode() == ISD::ADDCARRY) {
// This converts the boolean value carry into the carry flag.
@@ -7530,7 +7738,7 @@ static SDValue LowerADDSUBCARRY(SDValue Op, SelectionDAG &DAG) {
// Do the addition proper using the carry flag we wanted.
Result = DAG.getNode(ARMISD::ADDE, DL, VTs, Op.getOperand(0),
- Op.getOperand(1), Carry.getValue(1));
+ Op.getOperand(1), Carry);
// Now convert the carry flag into a boolean value.
Carry = ConvertCarryFlagToBooleanCarry(Result.getValue(1), VT, DAG);
@@ -7544,7 +7752,7 @@ static SDValue LowerADDSUBCARRY(SDValue Op, SelectionDAG &DAG) {
// Do the subtraction proper using the carry flag we wanted.
Result = DAG.getNode(ARMISD::SUBE, DL, VTs, Op.getOperand(0),
- Op.getOperand(1), Carry.getValue(1));
+ Op.getOperand(1), Carry);
// Now convert the carry flag into a boolean value.
Carry = ConvertCarryFlagToBooleanCarry(Result.getValue(1), VT, DAG);
@@ -7851,7 +8059,7 @@ static SDValue LowerFPOWI(SDValue Op, const ARMSubtarget &Subtarget,
}
SDValue ARMTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
- DEBUG(dbgs() << "Lowering node: "; Op.dump());
+ LLVM_DEBUG(dbgs() << "Lowering node: "; Op.dump());
switch (Op.getOpcode()) {
default: llvm_unreachable("Don't know how to custom lower this!");
case ISD::WRITE_REGISTER: return LowerWRITE_REGISTER(Op, DAG);
@@ -7879,7 +8087,7 @@ SDValue ARMTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
case ISD::EH_SJLJ_SETUP_DISPATCH: return LowerEH_SJLJ_SETUP_DISPATCH(Op, DAG);
case ISD::INTRINSIC_WO_CHAIN: return LowerINTRINSIC_WO_CHAIN(Op, DAG,
Subtarget);
- case ISD::BITCAST: return ExpandBITCAST(Op.getNode(), DAG);
+ case ISD::BITCAST: return ExpandBITCAST(Op.getNode(), DAG, Subtarget);
case ISD::SHL:
case ISD::SRL:
case ISD::SRA: return LowerShift(Op.getNode(), DAG, Subtarget);
@@ -7892,7 +8100,7 @@ SDValue ARMTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
case ISD::CTTZ_ZERO_UNDEF: return LowerCTTZ(Op.getNode(), DAG, Subtarget);
case ISD::CTPOP: return LowerCTPOP(Op.getNode(), DAG, Subtarget);
case ISD::SETCC: return LowerVSETCC(Op, DAG);
- case ISD::SETCCE: return LowerSETCCE(Op, DAG);
+ case ISD::SETCCCARRY: return LowerSETCCCARRY(Op, DAG);
case ISD::ConstantFP: return LowerConstantFP(Op, DAG, Subtarget);
case ISD::BUILD_VECTOR: return LowerBUILD_VECTOR(Op, DAG, Subtarget);
case ISD::VECTOR_SHUFFLE: return LowerVECTOR_SHUFFLE(Op, DAG);
@@ -7909,10 +8117,6 @@ SDValue ARMTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
if (Subtarget->isTargetWindows() && !Op.getValueType().isVector())
return LowerDIV_Windows(Op, DAG, /* Signed */ false);
return LowerUDIV(Op, DAG);
- case ISD::ADDC:
- case ISD::ADDE:
- case ISD::SUBC:
- case ISD::SUBE: return LowerADDC_ADDE_SUBC_SUBE(Op, DAG);
case ISD::ADDCARRY:
case ISD::SUBCARRY: return LowerADDSUBCARRY(Op, DAG);
case ISD::SADDO:
@@ -7927,7 +8131,7 @@ SDValue ARMTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
case ISD::SDIVREM:
case ISD::UDIVREM: return LowerDivRem(Op, DAG);
case ISD::DYNAMIC_STACKALLOC:
- if (Subtarget->getTargetTriple().isWindowsItaniumEnvironment())
+ if (Subtarget->isTargetWindows())
return LowerDYNAMIC_STACKALLOC(Op, DAG);
llvm_unreachable("Don't know how to custom lower this!");
case ISD::FP_ROUND: return LowerFP_ROUND(Op, DAG);
@@ -7981,7 +8185,7 @@ void ARMTargetLowering::ReplaceNodeResults(SDNode *N,
ExpandREAD_REGISTER(N, Results, DAG);
break;
case ISD::BITCAST:
- Res = ExpandBITCAST(N, DAG);
+ Res = ExpandBITCAST(N, DAG, Subtarget);
break;
case ISD::SRL:
case ISD::SRA:
@@ -9055,8 +9259,6 @@ ARMTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
// Thumb1 post-indexed loads are really just single-register LDMs.
case ARM::tLDR_postidx: {
MachineOperand Def(MI.getOperand(1));
- if (TargetRegisterInfo::isPhysicalRegister(Def.getReg()))
- Def.setIsRenamable(false);
BuildMI(*BB, MI, dl, TII->get(ARM::tLDMIA_UPD))
.add(Def) // Rn_wb
.add(MI.getOperand(2)) // Rn
@@ -9323,7 +9525,7 @@ ARMTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
}
}
-/// \brief Attaches vregs to MEMCPY that it will use as scratch registers
+/// Attaches vregs to MEMCPY that it will use as scratch registers
/// when it is expanded into LDM/STM. This is done as a post-isel lowering
/// instead of as a custom inserter because we need the use list from the SDNode.
static void attachMEMCPYScratchRegs(const ARMSubtarget *Subtarget,
@@ -9860,7 +10062,7 @@ static SDValue AddCombineTo64BitSMLAL16(SDNode *AddcNode, SDNode *AddeNode,
return resNode;
}
-static SDValue AddCombineTo64bitMLAL(SDNode *AddeNode,
+static SDValue AddCombineTo64bitMLAL(SDNode *AddeSubeNode,
TargetLowering::DAGCombinerInfo &DCI,
const ARMSubtarget *Subtarget) {
// Look for multiply add opportunities.
@@ -9877,49 +10079,61 @@ static SDValue AddCombineTo64bitMLAL(SDNode *AddeNode,
// V V
// ADDE <- hiAdd
//
- assert(AddeNode->getOpcode() == ARMISD::ADDE && "Expect an ADDE");
+ // In the special case where only the higher part of a signed result is used
+ // and the add to the low part of the result of ISD::UMUL_LOHI adds or subtracts
+ // a constant with the exact value of 0x80000000, we recognize we are dealing
+ // with a "rounded multiply and add" (or subtract) and transform it into
+ // either a ARMISD::SMMLAR or ARMISD::SMMLSR respectively.
+
+ assert((AddeSubeNode->getOpcode() == ARMISD::ADDE ||
+ AddeSubeNode->getOpcode() == ARMISD::SUBE) &&
+ "Expect an ADDE or SUBE");
- assert(AddeNode->getNumOperands() == 3 &&
- AddeNode->getOperand(2).getValueType() == MVT::i32 &&
+ assert(AddeSubeNode->getNumOperands() == 3 &&
+ AddeSubeNode->getOperand(2).getValueType() == MVT::i32 &&
"ADDE node has the wrong inputs");
- // Check that we are chained to the right ADDC node.
- SDNode* AddcNode = AddeNode->getOperand(2).getNode();
- if (AddcNode->getOpcode() != ARMISD::ADDC)
+ // Check that we are chained to the right ADDC or SUBC node.
+ SDNode *AddcSubcNode = AddeSubeNode->getOperand(2).getNode();
+ if ((AddeSubeNode->getOpcode() == ARMISD::ADDE &&
+ AddcSubcNode->getOpcode() != ARMISD::ADDC) ||
+ (AddeSubeNode->getOpcode() == ARMISD::SUBE &&
+ AddcSubcNode->getOpcode() != ARMISD::SUBC))
return SDValue();
- SDValue AddcOp0 = AddcNode->getOperand(0);
- SDValue AddcOp1 = AddcNode->getOperand(1);
+ SDValue AddcSubcOp0 = AddcSubcNode->getOperand(0);
+ SDValue AddcSubcOp1 = AddcSubcNode->getOperand(1);
// Check if the two operands are from the same mul_lohi node.
- if (AddcOp0.getNode() == AddcOp1.getNode())
+ if (AddcSubcOp0.getNode() == AddcSubcOp1.getNode())
return SDValue();
- assert(AddcNode->getNumValues() == 2 &&
- AddcNode->getValueType(0) == MVT::i32 &&
+ assert(AddcSubcNode->getNumValues() == 2 &&
+ AddcSubcNode->getValueType(0) == MVT::i32 &&
"Expect ADDC with two result values. First: i32");
// Check that the ADDC adds the low result of the S/UMUL_LOHI. If not, it
// maybe a SMLAL which multiplies two 16-bit values.
- if (AddcOp0->getOpcode() != ISD::UMUL_LOHI &&
- AddcOp0->getOpcode() != ISD::SMUL_LOHI &&
- AddcOp1->getOpcode() != ISD::UMUL_LOHI &&
- AddcOp1->getOpcode() != ISD::SMUL_LOHI)
- return AddCombineTo64BitSMLAL16(AddcNode, AddeNode, DCI, Subtarget);
+ if (AddeSubeNode->getOpcode() == ARMISD::ADDE &&
+ AddcSubcOp0->getOpcode() != ISD::UMUL_LOHI &&
+ AddcSubcOp0->getOpcode() != ISD::SMUL_LOHI &&
+ AddcSubcOp1->getOpcode() != ISD::UMUL_LOHI &&
+ AddcSubcOp1->getOpcode() != ISD::SMUL_LOHI)
+ return AddCombineTo64BitSMLAL16(AddcSubcNode, AddeSubeNode, DCI, Subtarget);
// Check for the triangle shape.
- SDValue AddeOp0 = AddeNode->getOperand(0);
- SDValue AddeOp1 = AddeNode->getOperand(1);
+ SDValue AddeSubeOp0 = AddeSubeNode->getOperand(0);
+ SDValue AddeSubeOp1 = AddeSubeNode->getOperand(1);
- // Make sure that the ADDE operands are not coming from the same node.
- if (AddeOp0.getNode() == AddeOp1.getNode())
+ // Make sure that the ADDE/SUBE operands are not coming from the same node.
+ if (AddeSubeOp0.getNode() == AddeSubeOp1.getNode())
return SDValue();
- // Find the MUL_LOHI node walking up ADDE's operands.
+ // Find the MUL_LOHI node walking up ADDE/SUBE's operands.
bool IsLeftOperandMUL = false;
- SDValue MULOp = findMUL_LOHI(AddeOp0);
+ SDValue MULOp = findMUL_LOHI(AddeSubeOp0);
if (MULOp == SDValue())
- MULOp = findMUL_LOHI(AddeOp1);
+ MULOp = findMUL_LOHI(AddeSubeOp1);
else
IsLeftOperandMUL = true;
if (MULOp == SDValue())
@@ -9930,63 +10144,88 @@ static SDValue AddCombineTo64bitMLAL(SDNode *AddeNode,
unsigned FinalOpc = (Opc == ISD::SMUL_LOHI) ? ARMISD::SMLAL : ARMISD::UMLAL;
// Figure out the high and low input values to the MLAL node.
- SDValue* HiAdd = nullptr;
- SDValue* LoMul = nullptr;
- SDValue* LowAdd = nullptr;
+ SDValue *HiAddSub = nullptr;
+ SDValue *LoMul = nullptr;
+ SDValue *LowAddSub = nullptr;
- // Ensure that ADDE is from high result of ISD::xMUL_LOHI.
- if ((AddeOp0 != MULOp.getValue(1)) && (AddeOp1 != MULOp.getValue(1)))
+ // Ensure that ADDE/SUBE is from high result of ISD::xMUL_LOHI.
+ if ((AddeSubeOp0 != MULOp.getValue(1)) && (AddeSubeOp1 != MULOp.getValue(1)))
return SDValue();
if (IsLeftOperandMUL)
- HiAdd = &AddeOp1;
+ HiAddSub = &AddeSubeOp1;
else
- HiAdd = &AddeOp0;
-
+ HiAddSub = &AddeSubeOp0;
- // Ensure that LoMul and LowAdd are taken from correct ISD::SMUL_LOHI node
- // whose low result is fed to the ADDC we are checking.
+ // Ensure that LoMul and LowAddSub are taken from correct ISD::SMUL_LOHI node
+ // whose low result is fed to the ADDC/SUBC we are checking.
- if (AddcOp0 == MULOp.getValue(0)) {
- LoMul = &AddcOp0;
- LowAdd = &AddcOp1;
+ if (AddcSubcOp0 == MULOp.getValue(0)) {
+ LoMul = &AddcSubcOp0;
+ LowAddSub = &AddcSubcOp1;
}
- if (AddcOp1 == MULOp.getValue(0)) {
- LoMul = &AddcOp1;
- LowAdd = &AddcOp0;
+ if (AddcSubcOp1 == MULOp.getValue(0)) {
+ LoMul = &AddcSubcOp1;
+ LowAddSub = &AddcSubcOp0;
}
if (!LoMul)
return SDValue();
- // If HiAdd is the same node as ADDC or is a predecessor of ADDC the
- // replacement below will create a cycle.
- if (AddcNode == HiAdd->getNode() ||
- AddcNode->isPredecessorOf(HiAdd->getNode()))
+ // If HiAddSub is the same node as ADDC/SUBC or is a predecessor of ADDC/SUBC
+ // the replacement below will create a cycle.
+ if (AddcSubcNode == HiAddSub->getNode() ||
+ AddcSubcNode->isPredecessorOf(HiAddSub->getNode()))
return SDValue();
// Create the merged node.
SelectionDAG &DAG = DCI.DAG;
- // Build operand list.
+ // Start building operand list.
SmallVector<SDValue, 8> Ops;
Ops.push_back(LoMul->getOperand(0));
Ops.push_back(LoMul->getOperand(1));
- Ops.push_back(*LowAdd);
- Ops.push_back(*HiAdd);
- SDValue MLALNode = DAG.getNode(FinalOpc, SDLoc(AddcNode),
+ // Check whether we can use SMMLAR, SMMLSR or SMMULR instead. For this to be
+ // the case, we must be doing signed multiplication and only use the higher
+ // part of the result of the MLAL, furthermore the LowAddSub must be a constant
+ // addition or subtraction with the value of 0x800000.
+ if (Subtarget->hasV6Ops() && Subtarget->hasDSP() && Subtarget->useMulOps() &&
+ FinalOpc == ARMISD::SMLAL && !AddeSubeNode->hasAnyUseOfValue(1) &&
+ LowAddSub->getNode()->getOpcode() == ISD::Constant &&
+ static_cast<ConstantSDNode *>(LowAddSub->getNode())->getZExtValue() ==
+ 0x80000000) {
+ Ops.push_back(*HiAddSub);
+ if (AddcSubcNode->getOpcode() == ARMISD::SUBC) {
+ FinalOpc = ARMISD::SMMLSR;
+ } else {
+ FinalOpc = ARMISD::SMMLAR;
+ }
+ SDValue NewNode = DAG.getNode(FinalOpc, SDLoc(AddcSubcNode), MVT::i32, Ops);
+ DAG.ReplaceAllUsesOfValueWith(SDValue(AddeSubeNode, 0), NewNode);
+
+ return SDValue(AddeSubeNode, 0);
+ } else if (AddcSubcNode->getOpcode() == ARMISD::SUBC)
+ // SMMLS is generated during instruction selection and the rest of this
+ // function can not handle the case where AddcSubcNode is a SUBC.
+ return SDValue();
+
+ // Finish building the operand list for {U/S}MLAL
+ Ops.push_back(*LowAddSub);
+ Ops.push_back(*HiAddSub);
+
+ SDValue MLALNode = DAG.getNode(FinalOpc, SDLoc(AddcSubcNode),
DAG.getVTList(MVT::i32, MVT::i32), Ops);
// Replace the ADDs' nodes uses by the MLA node's values.
SDValue HiMLALResult(MLALNode.getNode(), 1);
- DAG.ReplaceAllUsesOfValueWith(SDValue(AddeNode, 0), HiMLALResult);
+ DAG.ReplaceAllUsesOfValueWith(SDValue(AddeSubeNode, 0), HiMLALResult);
SDValue LoMLALResult(MLALNode.getNode(), 0);
- DAG.ReplaceAllUsesOfValueWith(SDValue(AddcNode, 0), LoMLALResult);
+ DAG.ReplaceAllUsesOfValueWith(SDValue(AddcSubcNode, 0), LoMLALResult);
// Return original node to notify the driver to stop replacing.
- return SDValue(AddeNode, 0);
+ return SDValue(AddeSubeNode, 0);
}
static SDValue AddCombineTo64bitUMAAL(SDNode *AddeNode,
@@ -10071,13 +10310,13 @@ static SDValue PerformAddcSubcCombine(SDNode *N,
const ARMSubtarget *Subtarget) {
SelectionDAG &DAG(DCI.DAG);
- if (N->getOpcode() == ARMISD::ADDC) {
- // (ADDC (ADDE 0, 0, C), -1) -> C
+ if (N->getOpcode() == ARMISD::SUBC) {
+ // (SUBC (ADDE 0, 0, C), 1) -> C
SDValue LHS = N->getOperand(0);
SDValue RHS = N->getOperand(1);
if (LHS->getOpcode() == ARMISD::ADDE &&
isNullConstant(LHS->getOperand(0)) &&
- isNullConstant(LHS->getOperand(1)) && isAllOnesConstant(RHS)) {
+ isNullConstant(LHS->getOperand(1)) && isOneConstant(RHS)) {
return DCI.CombineTo(N, SDValue(N, 0), LHS->getOperand(2));
}
}
@@ -10095,12 +10334,15 @@ static SDValue PerformAddcSubcCombine(SDNode *N,
}
}
}
+
return SDValue();
}
-static SDValue PerformAddeSubeCombine(SDNode *N, SelectionDAG &DAG,
+static SDValue PerformAddeSubeCombine(SDNode *N,
+ TargetLowering::DAGCombinerInfo &DCI,
const ARMSubtarget *Subtarget) {
if (Subtarget->isThumb1Only()) {
+ SelectionDAG &DAG = DCI.DAG;
SDValue RHS = N->getOperand(1);
if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(RHS)) {
int64_t imm = C->getSExtValue();
@@ -10118,6 +10360,8 @@ static SDValue PerformAddeSubeCombine(SDNode *N, SelectionDAG &DAG,
N->getOperand(0), RHS, N->getOperand(2));
}
}
+ } else if (N->getOperand(1)->getOpcode() == ISD::SMUL_LOHI) {
+ return AddCombineTo64bitMLAL(N, DCI, Subtarget);
}
return SDValue();
}
@@ -10130,7 +10374,7 @@ static SDValue PerformADDECombine(SDNode *N,
const ARMSubtarget *Subtarget) {
// Only ARM and Thumb2 support UMLAL/SMLAL.
if (Subtarget->isThumb1Only())
- return PerformAddeSubeCombine(N, DCI.DAG, Subtarget);
+ return PerformAddeSubeCombine(N, DCI, Subtarget);
// Only perform the checks after legalize when the pattern is available.
if (DCI.isBeforeLegalize()) return SDValue();
@@ -10201,7 +10445,14 @@ static SDValue PerformSHLSimplify(SDNode *N,
case ISD::XOR:
case ISD::SETCC:
case ARMISD::CMP:
- // Check that its not already using a shl.
+ // Check that the user isn't already using a constant because there
+ // aren't any instructions that support an immediate operand and a
+ // shifted operand.
+ if (isa<ConstantSDNode>(U->getOperand(0)) ||
+ isa<ConstantSDNode>(U->getOperand(1)))
+ return SDValue();
+
+ // Check that it's not already using a shift.
if (U->getOperand(0).getOpcode() == ISD::SHL ||
U->getOperand(1).getOpcode() == ISD::SHL)
return SDValue();
@@ -10223,8 +10474,6 @@ static SDValue PerformSHLSimplify(SDNode *N,
if (!C1ShlC2 || !C2)
return SDValue();
- DEBUG(dbgs() << "Trying to simplify shl: "; N->dump());
-
APInt C2Int = C2->getAPIntValue();
APInt C1Int = C1ShlC2->getAPIntValue();
@@ -10238,12 +10487,12 @@ static SDValue PerformSHLSimplify(SDNode *N,
C1Int.lshrInPlace(C2Int);
// The immediates are encoded as an 8-bit value that can be rotated.
- unsigned Zeros = C1Int.countLeadingZeros() + C1Int.countTrailingZeros();
- if (C1Int.getBitWidth() - Zeros > 8)
- return SDValue();
+ auto LargeImm = [](const APInt &Imm) {
+ unsigned Zeros = Imm.countLeadingZeros() + Imm.countTrailingZeros();
+ return Imm.getBitWidth() - Zeros > 8;
+ };
- Zeros = C2Int.countLeadingZeros() + C2Int.countTrailingZeros();
- if (C2Int.getBitWidth() - Zeros > 8)
+ if (LargeImm(C1Int) || LargeImm(C2Int))
return SDValue();
SelectionDAG &DAG = DCI.DAG;
@@ -10254,6 +10503,10 @@ static SDValue PerformSHLSimplify(SDNode *N,
// Shift left to compensate for the lshr of C1Int.
SDValue Res = DAG.getNode(ISD::SHL, dl, MVT::i32, BinOp, SHL.getOperand(1));
+ LLVM_DEBUG(dbgs() << "Simplify shl use:\n"; SHL.getOperand(0).dump();
+ SHL.dump(); N->dump());
+ LLVM_DEBUG(dbgs() << "Into:\n"; X.dump(); BinOp.dump(); Res.dump());
+
DAG.ReplaceAllUsesWith(SDValue(N, 0), Res);
return SDValue(N, 0);
}
@@ -10423,6 +10676,83 @@ static SDValue PerformMULCombine(SDNode *N,
return SDValue();
}
+static SDValue CombineANDShift(SDNode *N,
+ TargetLowering::DAGCombinerInfo &DCI,
+ const ARMSubtarget *Subtarget) {
+ // Allow DAGCombine to pattern-match before we touch the canonical form.
+ if (DCI.isBeforeLegalize() || DCI.isCalledByLegalizer())
+ return SDValue();
+
+ if (N->getValueType(0) != MVT::i32)
+ return SDValue();
+
+ ConstantSDNode *N1C = dyn_cast<ConstantSDNode>(N->getOperand(1));
+ if (!N1C)
+ return SDValue();
+
+ uint32_t C1 = (uint32_t)N1C->getZExtValue();
+ // Don't transform uxtb/uxth.
+ if (C1 == 255 || C1 == 65535)
+ return SDValue();
+
+ SDNode *N0 = N->getOperand(0).getNode();
+ if (!N0->hasOneUse())
+ return SDValue();
+
+ if (N0->getOpcode() != ISD::SHL && N0->getOpcode() != ISD::SRL)
+ return SDValue();
+
+ bool LeftShift = N0->getOpcode() == ISD::SHL;
+
+ ConstantSDNode *N01C = dyn_cast<ConstantSDNode>(N0->getOperand(1));
+ if (!N01C)
+ return SDValue();
+
+ uint32_t C2 = (uint32_t)N01C->getZExtValue();
+ if (!C2 || C2 >= 32)
+ return SDValue();
+
+ SelectionDAG &DAG = DCI.DAG;
+ SDLoc DL(N);
+
+ // We have a pattern of the form "(and (shl x, c2) c1)" or
+ // "(and (srl x, c2) c1)", where c1 is a shifted mask. Try to
+ // transform to a pair of shifts, to save materializing c1.
+
+ // First pattern: right shift, and c1+1 is a power of two.
+ // FIXME: Also check reversed pattern (left shift, and ~c1+1 is a power
+ // of two).
+ // FIXME: Use demanded bits?
+ if (!LeftShift && isMask_32(C1)) {
+ uint32_t C3 = countLeadingZeros(C1);
+ if (C2 < C3) {
+ SDValue SHL = DAG.getNode(ISD::SHL, DL, MVT::i32, N0->getOperand(0),
+ DAG.getConstant(C3 - C2, DL, MVT::i32));
+ return DAG.getNode(ISD::SRL, DL, MVT::i32, SHL,
+ DAG.getConstant(C3, DL, MVT::i32));
+ }
+ }
+
+ // Second pattern: left shift, and (c1>>c2)+1 is a power of two.
+ // FIXME: Also check reversed pattern (right shift, and ~(c1<<c2)+1
+ // is a power of two).
+ // FIXME: Use demanded bits?
+ if (LeftShift && isShiftedMask_32(C1)) {
+ uint32_t C3 = countLeadingZeros(C1);
+ if (C2 + C3 < 32 && C1 == ((-1U << (C2 + C3)) >> C3)) {
+ SDValue SHL = DAG.getNode(ISD::SHL, DL, MVT::i32, N0->getOperand(0),
+ DAG.getConstant(C2 + C3, DL, MVT::i32));
+ return DAG.getNode(ISD::SRL, DL, MVT::i32, SHL,
+ DAG.getConstant(C3, DL, MVT::i32));
+ }
+ }
+
+ // FIXME: Transform "(and (shl x, c2) c1)" ->
+ // "(shl (and x, c1>>c2), c2)" if "c1 >> c2" is a cheaper immediate than
+ // c1.
+ return SDValue();
+}
+
static SDValue PerformANDCombine(SDNode *N,
TargetLowering::DAGCombinerInfo &DCI,
const ARMSubtarget *Subtarget) {
@@ -10464,6 +10794,10 @@ static SDValue PerformANDCombine(SDNode *N,
return Result;
}
+ if (Subtarget->isThumb1Only())
+ if (SDValue Result = CombineANDShift(N, DCI, Subtarget))
+ return Result;
+
return SDValue();
}
@@ -11012,7 +11346,7 @@ static SDValue PerformBUILD_VECTORCombine(SDNode *N,
return DAG.getNode(ISD::BITCAST, dl, VT, BV);
}
-/// \brief Target-specific dag combine xforms for ARMISD::BUILD_VECTOR.
+/// Target-specific dag combine xforms for ARMISD::BUILD_VECTOR.
static SDValue
PerformARMBUILD_VECTORCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI) {
// ARMISD::BUILD_VECTOR is introduced when legalizing ISD::BUILD_VECTOR.
@@ -11228,6 +11562,12 @@ static SDValue CombineBaseUpdate(SDNode *N,
NumVecs = 3; break;
case Intrinsic::arm_neon_vld4: NewOpc = ARMISD::VLD4_UPD;
NumVecs = 4; break;
+ case Intrinsic::arm_neon_vld2dup:
+ case Intrinsic::arm_neon_vld3dup:
+ case Intrinsic::arm_neon_vld4dup:
+ // TODO: Support updating VLDxDUP nodes. For now, we just skip
+ // combining base updates for such intrinsics.
+ continue;
case Intrinsic::arm_neon_vld2lane: NewOpc = ARMISD::VLD2LN_UPD;
NumVecs = 2; isLaneOp = true; break;
case Intrinsic::arm_neon_vld3lane: NewOpc = ARMISD::VLD3LN_UPD;
@@ -12306,6 +12646,89 @@ ARMTargetLowering::PerformCMOVCombine(SDNode *N, SelectionDAG &DAG) const {
}
}
+ if (!VT.isInteger())
+ return SDValue();
+
+ // Materialize a boolean comparison for integers so we can avoid branching.
+ if (isNullConstant(FalseVal)) {
+ if (CC == ARMCC::EQ && isOneConstant(TrueVal)) {
+ if (!Subtarget->isThumb1Only() && Subtarget->hasV5TOps()) {
+ // If x == y then x - y == 0 and ARM's CLZ will return 32, shifting it
+ // right 5 bits will make that 32 be 1, otherwise it will be 0.
+ // CMOV 0, 1, ==, (CMPZ x, y) -> SRL (CTLZ (SUB x, y)), 5
+ SDValue Sub = DAG.getNode(ISD::SUB, dl, VT, LHS, RHS);
+ Res = DAG.getNode(ISD::SRL, dl, VT, DAG.getNode(ISD::CTLZ, dl, VT, Sub),
+ DAG.getConstant(5, dl, MVT::i32));
+ } else {
+ // CMOV 0, 1, ==, (CMPZ x, y) ->
+ // (ADDCARRY (SUB x, y), t:0, t:1)
+ // where t = (SUBCARRY 0, (SUB x, y), 0)
+ //
+ // The SUBCARRY computes 0 - (x - y) and this will give a borrow when
+ // x != y. In other words, a carry C == 1 when x == y, C == 0
+ // otherwise.
+ // The final ADDCARRY computes
+ // x - y + (0 - (x - y)) + C == C
+ SDValue Sub = DAG.getNode(ISD::SUB, dl, VT, LHS, RHS);
+ SDVTList VTs = DAG.getVTList(VT, MVT::i32);
+ SDValue Neg = DAG.getNode(ISD::USUBO, dl, VTs, FalseVal, Sub);
+ // ISD::SUBCARRY returns a borrow but we want the carry here
+ // actually.
+ SDValue Carry =
+ DAG.getNode(ISD::SUB, dl, MVT::i32,
+ DAG.getConstant(1, dl, MVT::i32), Neg.getValue(1));
+ Res = DAG.getNode(ISD::ADDCARRY, dl, VTs, Sub, Neg, Carry);
+ }
+ } else if (CC == ARMCC::NE && LHS != RHS &&
+ (!Subtarget->isThumb1Only() || isPowerOf2Constant(TrueVal))) {
+ // This seems pointless but will allow us to combine it further below.
+ // CMOV 0, z, !=, (CMPZ x, y) -> CMOV (SUB x, y), z, !=, (CMPZ x, y)
+ SDValue Sub = DAG.getNode(ISD::SUB, dl, VT, LHS, RHS);
+ Res = DAG.getNode(ARMISD::CMOV, dl, VT, Sub, TrueVal, ARMcc,
+ N->getOperand(3), Cmp);
+ }
+ } else if (isNullConstant(TrueVal)) {
+ if (CC == ARMCC::EQ && LHS != RHS &&
+ (!Subtarget->isThumb1Only() || isPowerOf2Constant(FalseVal))) {
+ // This seems pointless but will allow us to combine it further below
+ // Note that we change == for != as this is the dual for the case above.
+ // CMOV z, 0, ==, (CMPZ x, y) -> CMOV (SUB x, y), z, !=, (CMPZ x, y)
+ SDValue Sub = DAG.getNode(ISD::SUB, dl, VT, LHS, RHS);
+ Res = DAG.getNode(ARMISD::CMOV, dl, VT, Sub, FalseVal,
+ DAG.getConstant(ARMCC::NE, dl, MVT::i32),
+ N->getOperand(3), Cmp);
+ }
+ }
+
+ // On Thumb1, the DAG above may be further combined if z is a power of 2
+ // (z == 2 ^ K).
+ // CMOV (SUB x, y), z, !=, (CMPZ x, y) ->
+ // merge t3, t4
+ // where t1 = (SUBCARRY (SUB x, y), z, 0)
+ // t2 = (SUBCARRY (SUB x, y), t1:0, t1:1)
+ // t3 = if K != 0 then (SHL t2:0, K) else t2:0
+ // t4 = (SUB 1, t2:1) [ we want a carry, not a borrow ]
+ const APInt *TrueConst;
+ if (Subtarget->isThumb1Only() && CC == ARMCC::NE &&
+ (FalseVal.getOpcode() == ISD::SUB) && (FalseVal.getOperand(0) == LHS) &&
+ (FalseVal.getOperand(1) == RHS) &&
+ (TrueConst = isPowerOf2Constant(TrueVal))) {
+ SDVTList VTs = DAG.getVTList(VT, MVT::i32);
+ unsigned ShiftAmount = TrueConst->logBase2();
+ if (ShiftAmount)
+ TrueVal = DAG.getConstant(1, dl, VT);
+ SDValue Subc = DAG.getNode(ISD::USUBO, dl, VTs, FalseVal, TrueVal);
+ Res = DAG.getNode(ISD::SUBCARRY, dl, VTs, FalseVal, Subc, Subc.getValue(1));
+ // Make it a carry, not a borrow.
+ SDValue Carry = DAG.getNode(
+ ISD::SUB, dl, VT, DAG.getConstant(1, dl, MVT::i32), Res.getValue(1));
+ Res = DAG.getNode(ISD::MERGE_VALUES, dl, VTs, Res, Carry);
+
+ if (ShiftAmount)
+ Res = DAG.getNode(ISD::SHL, dl, VT, Res,
+ DAG.getConstant(ShiftAmount, dl, MVT::i32));
+ }
+
if (Res.getNode()) {
KnownBits Known;
DAG.computeKnownBits(SDValue(N,0), Known);
@@ -12338,7 +12761,7 @@ SDValue ARMTargetLowering::PerformDAGCombine(SDNode *N,
case ISD::AND: return PerformANDCombine(N, DCI, Subtarget);
case ARMISD::ADDC:
case ARMISD::SUBC: return PerformAddcSubcCombine(N, DCI, Subtarget);
- case ARMISD::SUBE: return PerformAddeSubeCombine(N, DCI.DAG, Subtarget);
+ case ARMISD::SUBE: return PerformAddeSubeCombine(N, DCI, Subtarget);
case ARMISD::BFI: return PerformBFICombine(N, DCI);
case ARMISD::VMOVRRD: return PerformVMOVRRDCombine(N, DCI, Subtarget);
case ARMISD::VMOVDRR: return PerformVMOVDRRCombine(N, DCI.DAG);
@@ -12424,13 +12847,22 @@ SDValue ARMTargetLowering::PerformDAGCombine(SDNode *N,
case ISD::INTRINSIC_W_CHAIN:
switch (cast<ConstantSDNode>(N->getOperand(1))->getZExtValue()) {
case Intrinsic::arm_neon_vld1:
+ case Intrinsic::arm_neon_vld1x2:
+ case Intrinsic::arm_neon_vld1x3:
+ case Intrinsic::arm_neon_vld1x4:
case Intrinsic::arm_neon_vld2:
case Intrinsic::arm_neon_vld3:
case Intrinsic::arm_neon_vld4:
case Intrinsic::arm_neon_vld2lane:
case Intrinsic::arm_neon_vld3lane:
case Intrinsic::arm_neon_vld4lane:
+ case Intrinsic::arm_neon_vld2dup:
+ case Intrinsic::arm_neon_vld3dup:
+ case Intrinsic::arm_neon_vld4dup:
case Intrinsic::arm_neon_vst1:
+ case Intrinsic::arm_neon_vst1x2:
+ case Intrinsic::arm_neon_vst1x3:
+ case Intrinsic::arm_neon_vst1x4:
case Intrinsic::arm_neon_vst2:
case Intrinsic::arm_neon_vst3:
case Intrinsic::arm_neon_vst4:
@@ -12454,6 +12886,10 @@ bool ARMTargetLowering::allowsMisalignedMemoryAccesses(EVT VT,
unsigned,
unsigned,
bool *Fast) const {
+ // Depends what it gets converted into if the type is weird.
+ if (!VT.isSimple())
+ return false;
+
// The AllowsUnaliged flag models the SCTLR.A setting in ARM cpus
bool AllowsUnaligned = Subtarget->allowsUnalignedMem();
@@ -12560,6 +12996,24 @@ bool ARMTargetLowering::isZExtFree(SDValue Val, EVT VT2) const {
return false;
}
+bool ARMTargetLowering::isFNegFree(EVT VT) const {
+ if (!VT.isSimple())
+ return false;
+
+ // There are quite a few FP16 instructions (e.g. VNMLA, VNMLS, etc.) that
+ // negate values directly (fneg is free). So, we don't want to let the DAG
+ // combiner rewrite fneg into xors and some other instructions. For f16 and
+ // FullFP16 argument passing, some bitcast nodes may be introduced,
+ // triggering this DAG combine rewrite, so we are avoiding that with this.
+ switch (VT.getSimpleVT().SimpleTy) {
+ default: break;
+ case MVT::f16:
+ return Subtarget->hasFullFP16();
+ }
+
+ return false;
+}
+
bool ARMTargetLowering::isVectorLoadExtDesirable(SDValue ExtVal) const {
EVT VT = ExtVal.getValueType();
@@ -12828,9 +13282,11 @@ bool ARMTargetLowering::isLegalAddressingMode(const DataLayout &DL,
bool ARMTargetLowering::isLegalICmpImmediate(int64_t Imm) const {
// Thumb2 and ARM modes can use cmn for negative immediates.
if (!Subtarget->isThumb())
- return ARM_AM::getSOImmVal(std::abs(Imm)) != -1;
+ return ARM_AM::getSOImmVal((uint32_t)Imm) != -1 ||
+ ARM_AM::getSOImmVal(-(uint32_t)Imm) != -1;
if (Subtarget->isThumb2())
- return ARM_AM::getT2SOImmVal(std::abs(Imm)) != -1;
+ return ARM_AM::getT2SOImmVal((uint32_t)Imm) != -1 ||
+ ARM_AM::getT2SOImmVal(-(uint32_t)Imm) != -1;
// Thumb1 doesn't have cmn, and only 8-bit immediates.
return Imm >= 0 && Imm <= 255;
}
@@ -13262,8 +13718,14 @@ RCPair ARMTargetLowering::getRegForInlineAsmConstraint(
return RCPair(0U, &ARM::QPR_8RegClass);
break;
case 't':
+ if (VT == MVT::Other)
+ break;
if (VT == MVT::f32 || VT == MVT::i32)
return RCPair(0U, &ARM::SPRRegClass);
+ if (VT.getSizeInBits() == 64)
+ return RCPair(0U, &ARM::DPR_VFP2RegClass);
+ if (VT.getSizeInBits() == 128)
+ return RCPair(0U, &ARM::QPR_VFP2RegClass);
break;
}
}
@@ -13593,6 +14055,20 @@ ARMTargetLowering::LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) const
SDValue Chain = Op.getOperand(0);
SDValue Size = Op.getOperand(1);
+ if (DAG.getMachineFunction().getFunction().hasFnAttribute(
+ "no-stack-arg-probe")) {
+ unsigned Align = cast<ConstantSDNode>(Op.getOperand(2))->getZExtValue();
+ SDValue SP = DAG.getCopyFromReg(Chain, DL, ARM::SP, MVT::i32);
+ Chain = SP.getValue(1);
+ SP = DAG.getNode(ISD::SUB, DL, MVT::i32, SP, Size);
+ if (Align)
+ SP = DAG.getNode(ISD::AND, DL, MVT::i32, SP.getValue(0),
+ DAG.getConstant(-(uint64_t)Align, DL, MVT::i32));
+ Chain = DAG.getCopyToReg(Chain, DL, ARM::SP, SP);
+ SDValue Ops[2] = { SP, Chain };
+ return DAG.getMergeValues(Ops, DL);
+ }
+
SDValue Words = DAG.getNode(ISD::SRL, DL, MVT::i32, Size,
DAG.getConstant(2, DL, MVT::i32));
@@ -13656,6 +14132,8 @@ bool ARM::isBitFieldInvertedMask(unsigned v) {
bool ARMTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT) const {
if (!Subtarget->hasVFP3())
return false;
+ if (VT == MVT::f16 && Subtarget->hasFullFP16())
+ return ARM_AM::getFP16Imm(Imm) != -1;
if (VT == MVT::f32)
return ARM_AM::getFP32Imm(Imm) != -1;
if (VT == MVT::f64 && !Subtarget->isFPOnlySP())
@@ -13677,7 +14155,10 @@ bool ARMTargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info,
case Intrinsic::arm_neon_vld4:
case Intrinsic::arm_neon_vld2lane:
case Intrinsic::arm_neon_vld3lane:
- case Intrinsic::arm_neon_vld4lane: {
+ case Intrinsic::arm_neon_vld4lane:
+ case Intrinsic::arm_neon_vld2dup:
+ case Intrinsic::arm_neon_vld3dup:
+ case Intrinsic::arm_neon_vld4dup: {
Info.opc = ISD::INTRINSIC_W_CHAIN;
// Conservatively set memVT to the entire set of vectors loaded.
auto &DL = I.getCalledFunction()->getParent()->getDataLayout();
@@ -13691,6 +14172,21 @@ bool ARMTargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info,
Info.flags = MachineMemOperand::MOLoad;
return true;
}
+ case Intrinsic::arm_neon_vld1x2:
+ case Intrinsic::arm_neon_vld1x3:
+ case Intrinsic::arm_neon_vld1x4: {
+ Info.opc = ISD::INTRINSIC_W_CHAIN;
+ // Conservatively set memVT to the entire set of vectors loaded.
+ auto &DL = I.getCalledFunction()->getParent()->getDataLayout();
+ uint64_t NumElts = DL.getTypeSizeInBits(I.getType()) / 64;
+ Info.memVT = EVT::getVectorVT(I.getType()->getContext(), MVT::i64, NumElts);
+ Info.ptrVal = I.getArgOperand(I.getNumArgOperands() - 1);
+ Info.offset = 0;
+ Info.align = 0;
+ // volatile loads with NEON intrinsics not supported
+ Info.flags = MachineMemOperand::MOLoad;
+ return true;
+ }
case Intrinsic::arm_neon_vst1:
case Intrinsic::arm_neon_vst2:
case Intrinsic::arm_neon_vst3:
@@ -13717,6 +14213,27 @@ bool ARMTargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info,
Info.flags = MachineMemOperand::MOStore;
return true;
}
+ case Intrinsic::arm_neon_vst1x2:
+ case Intrinsic::arm_neon_vst1x3:
+ case Intrinsic::arm_neon_vst1x4: {
+ Info.opc = ISD::INTRINSIC_VOID;
+ // Conservatively set memVT to the entire set of vectors stored.
+ auto &DL = I.getCalledFunction()->getParent()->getDataLayout();
+ unsigned NumElts = 0;
+ for (unsigned ArgI = 1, ArgE = I.getNumArgOperands(); ArgI < ArgE; ++ArgI) {
+ Type *ArgTy = I.getArgOperand(ArgI)->getType();
+ if (!ArgTy->isVectorTy())
+ break;
+ NumElts += DL.getTypeSizeInBits(ArgTy) / 64;
+ }
+ Info.memVT = EVT::getVectorVT(I.getType()->getContext(), MVT::i64, NumElts);
+ Info.ptrVal = I.getArgOperand(0);
+ Info.offset = 0;
+ Info.align = 0;
+ // volatile stores with NEON intrinsics not supported
+ Info.flags = MachineMemOperand::MOStore;
+ return true;
+ }
case Intrinsic::arm_ldaex:
case Intrinsic::arm_ldrex: {
auto &DL = I.getCalledFunction()->getParent()->getDataLayout();
@@ -13768,7 +14285,7 @@ bool ARMTargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info,
return false;
}
-/// \brief Returns true if it is beneficial to convert a load of a constant
+/// Returns true if it is beneficial to convert a load of a constant
/// to just the constant itself.
bool ARMTargetLowering::shouldConvertConstantLoadToIntImm(const APInt &Imm,
Type *Ty) const {
@@ -14064,7 +14581,7 @@ bool ARMTargetLowering::isLegalInterleavedAccessType(
return VecSize == 64 || VecSize % 128 == 0;
}
-/// \brief Lower an interleaved load into a vldN intrinsic.
+/// Lower an interleaved load into a vldN intrinsic.
///
/// E.g. Lower an interleaved load (Factor = 2):
/// %wide.vec = load <8 x i32>, <8 x i32>* %ptr, align 4
@@ -14182,7 +14699,7 @@ bool ARMTargetLowering::lowerInterleavedLoad(
return true;
}
-/// \brief Lower an interleaved store into a vstN intrinsic.
+/// Lower an interleaved store into a vstN intrinsic.
///
/// E.g. Lower an interleaved store (Factor = 3):
/// %i.vec = shuffle <8 x i32> %v0, <8 x i32> %v1,
@@ -14380,7 +14897,19 @@ static bool isHomogeneousAggregate(Type *Ty, HABaseType &Base,
return (Members > 0 && Members <= 4);
}
-/// \brief Return true if a type is an AAPCS-VFP homogeneous aggregate or one of
+/// Return the correct alignment for the current calling convention.
+unsigned
+ARMTargetLowering::getABIAlignmentForCallingConv(Type *ArgTy,
+ DataLayout DL) const {
+ if (!ArgTy->isVectorTy())
+ return DL.getABITypeAlignment(ArgTy);
+
+ // Avoid over-aligning vector parameters. It would require realigning the
+ // stack and waste space for no real benefit.
+ return std::min(DL.getABITypeAlignment(ArgTy), DL.getStackAlignment());
+}
+
+/// Return true if a type is an AAPCS-VFP homogeneous aggregate or one of
/// [N x i32] or [N x i64]. This allows front-ends to skip emitting padding when
/// passing according to AAPCS rules.
bool ARMTargetLowering::functionArgumentNeedsConsecutiveRegisters(
@@ -14392,7 +14921,7 @@ bool ARMTargetLowering::functionArgumentNeedsConsecutiveRegisters(
HABaseType Base = HA_UNKNOWN;
uint64_t Members = 0;
bool IsHA = isHomogeneousAggregate(Ty, Base, Members);
- DEBUG(dbgs() << "isHA: " << IsHA << " "; Ty->dump());
+ LLVM_DEBUG(dbgs() << "isHA: " << IsHA << " "; Ty->dump());
bool IsIntArray = Ty->isArrayTy() && Ty->getArrayElementType()->isIntegerTy();
return IsHA || IsIntArray;
diff --git a/lib/Target/ARM/ARMISelLowering.h b/lib/Target/ARM/ARMISelLowering.h
index bf63dfae4407..50b4c2977fb5 100644
--- a/lib/Target/ARM/ARMISelLowering.h
+++ b/lib/Target/ARM/ARMISelLowering.h
@@ -21,7 +21,6 @@
#include "llvm/CodeGen/CallingConvLower.h"
#include "llvm/CodeGen/ISDOpcodes.h"
#include "llvm/CodeGen/MachineFunction.h"
-#include "llvm/CodeGen/MachineValueType.h"
#include "llvm/CodeGen/SelectionDAGNodes.h"
#include "llvm/CodeGen/TargetLowering.h"
#include "llvm/CodeGen/ValueTypes.h"
@@ -31,6 +30,7 @@
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/InlineAsm.h"
#include "llvm/Support/CodeGen.h"
+#include "llvm/Support/MachineValueType.h"
#include <utility>
namespace llvm {
@@ -102,6 +102,7 @@ class VectorType;
VMOVRRD, // double to two gprs.
VMOVDRR, // Two gprs to double.
+ VMOVSR, // move gpr to single, used for f32 literal constructed in a gpr
EH_SJLJ_SETJMP, // SjLj exception handling setjmp.
EH_SJLJ_LONGJMP, // SjLj exception handling longjmp.
@@ -171,6 +172,10 @@ class VectorType;
// Vector move f32 immediate:
VMOVFPIMM,
+ // Move H <-> R, clearing top 16 bits
+ VMOVrh,
+ VMOVhr,
+
// Vector duplicate:
VDUP,
VDUPLANE,
@@ -203,6 +208,8 @@ class VectorType;
SMLALDX, // Signed multiply accumulate long dual exchange
SMLSLD, // Signed multiply subtract long dual
SMLSLDX, // Signed multiply subtract long dual exchange
+ SMMLAR, // Signed multiply long, round and add
+ SMMLSR, // Signed multiply long, subtract and round
// Operands of the standard BUILD_VECTOR node are not legalized, which
// is fine if BUILD_VECTORs are always lowered to shuffles or other
@@ -325,6 +332,7 @@ class VectorType;
bool isTruncateFree(Type *SrcTy, Type *DstTy) const override;
bool isTruncateFree(EVT SrcVT, EVT DstVT) const override;
bool isZExtFree(SDValue Val, EVT VT2) const override;
+ bool isFNegFree(EVT VT) const override;
bool isVectorLoadExtDesirable(SDValue ExtVal) const override;
@@ -346,7 +354,7 @@ class VectorType;
bool isLegalT2ScaledAddressingMode(const AddrMode &AM, EVT VT) const;
- /// \brief Returns true if the addresing mode representing by AM is legal
+ /// Returns true if the addresing mode representing by AM is legal
/// for the Thumb1 target, for a load/store of the specified type.
bool isLegalT1ScaledAddressingMode(const AddrMode &AM, EVT VT) const;
@@ -474,7 +482,7 @@ class VectorType;
MachineFunction &MF,
unsigned Intrinsic) const override;
- /// \brief Returns true if it is beneficial to convert a load of a constant
+ /// Returns true if it is beneficial to convert a load of a constant
/// to just the constant itself.
bool shouldConvertConstantLoadToIntImm(const APInt &Imm,
Type *Ty) const override;
@@ -484,7 +492,7 @@ class VectorType;
bool isExtractSubvectorCheap(EVT ResVT, EVT SrcVT,
unsigned Index) const override;
- /// \brief Returns true if an argument of type Ty needs to be passed in a
+ /// Returns true if an argument of type Ty needs to be passed in a
/// contiguous block of registers in calling convention CallConv.
bool functionArgumentNeedsConsecutiveRegisters(
Type *Ty, CallingConv::ID CallConv, bool isVarArg) const override;
@@ -571,6 +579,10 @@ class VectorType;
void finalizeLowering(MachineFunction &MF) const override;
+ /// Return the correct alignment for the current calling convention.
+ unsigned getABIAlignmentForCallingConv(Type *ArgTy,
+ DataLayout DL) const override;
+
protected:
std::pair<const TargetRegisterClass *, uint8_t>
findRepresentativeClass(const TargetRegisterInfo *TRI,
diff --git a/lib/Target/ARM/ARMInstrFormats.td b/lib/Target/ARM/ARMInstrFormats.td
index f7c6c32eb4dc..70aded247f65 100644
--- a/lib/Target/ARM/ARMInstrFormats.td
+++ b/lib/Target/ARM/ARMInstrFormats.td
@@ -108,6 +108,7 @@ def AddrModeT2_so : AddrMode<13>;
def AddrModeT2_pc : AddrMode<14>;
def AddrModeT2_i8s4 : AddrMode<15>;
def AddrMode_i12 : AddrMode<16>;
+def AddrMode5FP16 : AddrMode<17>;
// Load / store index mode.
class IndexMode<bits<2> val> {
@@ -1023,6 +1024,12 @@ class Thumb2DSPPat<dag pattern, dag result> : Pat<pattern, result> {
class Thumb2DSPMulPat<dag pattern, dag result> : Pat<pattern, result> {
list<Predicate> Predicates = [IsThumb2, UseMulOps, HasDSP];
}
+class FP16Pat<dag pattern, dag result> : Pat<pattern, result> {
+ list<Predicate> Predicates = [HasFP16];
+}
+class FullFP16Pat<dag pattern, dag result> : Pat<pattern, result> {
+ list<Predicate> Predicates = [HasFullFP16];
+}
//===----------------------------------------------------------------------===//
// Thumb Instruction Format Definitions.
//
@@ -1527,7 +1534,7 @@ class ASI5<bits<4> opcod1, bits<2> opcod2, dag oops, dag iops,
class AHI5<bits<4> opcod1, bits<2> opcod2, dag oops, dag iops,
InstrItinClass itin,
string opc, string asm, list<dag> pattern>
- : VFPI<oops, iops, AddrMode5, 4, IndexModeNone,
+ : VFPI<oops, iops, AddrMode5FP16, 4, IndexModeNone,
VFPLdStFrm, itin, opc, asm, "", pattern> {
list<Predicate> Predicates = [HasFullFP16];
diff --git a/lib/Target/ARM/ARMInstrInfo.cpp b/lib/Target/ARM/ARMInstrInfo.cpp
index a0e2ac4cbc6f..397c9dadb4ac 100644
--- a/lib/Target/ARM/ARMInstrInfo.cpp
+++ b/lib/Target/ARM/ARMInstrInfo.cpp
@@ -135,3 +135,31 @@ void ARMInstrInfo::expandLoadStackGuard(MachineBasicBlock::iterator MI) const {
.setMemRefs(MI->memoperands_begin(), MI->memoperands_end())
.add(predOps(ARMCC::AL));
}
+
+std::pair<unsigned, unsigned>
+ARMInstrInfo::decomposeMachineOperandsTargetFlags(unsigned TF) const {
+ const unsigned Mask = ARMII::MO_OPTION_MASK;
+ return std::make_pair(TF & Mask, TF & ~Mask);
+}
+
+ArrayRef<std::pair<unsigned, const char *>>
+ARMInstrInfo::getSerializableDirectMachineOperandTargetFlags() const {
+ using namespace ARMII;
+
+ static const std::pair<unsigned, const char *> TargetFlags[] = {
+ {MO_LO16, "arm-lo16"}, {MO_HI16, "arm-hi16"}};
+ return makeArrayRef(TargetFlags);
+}
+
+ArrayRef<std::pair<unsigned, const char *>>
+ARMInstrInfo::getSerializableBitmaskMachineOperandTargetFlags() const {
+ using namespace ARMII;
+
+ static const std::pair<unsigned, const char *> TargetFlags[] = {
+ {MO_GOT, "arm-got"},
+ {MO_SBREL, "arm-sbrel"},
+ {MO_DLLIMPORT, "arm-dllimport"},
+ {MO_SECREL, "arm-secrel"},
+ {MO_NONLAZY, "arm-nonlazy"}};
+ return makeArrayRef(TargetFlags);
+}
diff --git a/lib/Target/ARM/ARMInstrInfo.h b/lib/Target/ARM/ARMInstrInfo.h
index c87fb97448c9..c54c987134df 100644
--- a/lib/Target/ARM/ARMInstrInfo.h
+++ b/lib/Target/ARM/ARMInstrInfo.h
@@ -38,6 +38,13 @@ public:
///
const ARMRegisterInfo &getRegisterInfo() const override { return RI; }
+ std::pair<unsigned, unsigned>
+ decomposeMachineOperandsTargetFlags(unsigned TF) const override;
+ ArrayRef<std::pair<unsigned, const char *>>
+ getSerializableDirectMachineOperandTargetFlags() const override;
+ ArrayRef<std::pair<unsigned, const char *>>
+ getSerializableBitmaskMachineOperandTargetFlags() const override;
+
private:
void expandLoadStackGuard(MachineBasicBlock::iterator MI) const override;
};
diff --git a/lib/Target/ARM/ARMInstrInfo.td b/lib/Target/ARM/ARMInstrInfo.td
index eb8526bfeadf..d4c342cee5c0 100644
--- a/lib/Target/ARM/ARMInstrInfo.td
+++ b/lib/Target/ARM/ARMInstrInfo.td
@@ -105,6 +105,14 @@ def ARMSmlaldx : SDNode<"ARMISD::SMLALDX", SDT_LongMac>;
def ARMSmlsld : SDNode<"ARMISD::SMLSLD", SDT_LongMac>;
def ARMSmlsldx : SDNode<"ARMISD::SMLSLDX", SDT_LongMac>;
+def SDT_MulHSR : SDTypeProfile<1, 3, [SDTCisVT<0,i32>,
+ SDTCisSameAs<0, 1>,
+ SDTCisSameAs<0, 2>,
+ SDTCisSameAs<0, 3>]>;
+
+def ARMsmmlar : SDNode<"ARMISD::SMMLAR", SDT_MulHSR>;
+def ARMsmmlsr : SDNode<"ARMISD::SMMLSR", SDT_MulHSR>;
+
// Node definitions.
def ARMWrapper : SDNode<"ARMISD::Wrapper", SDTIntUnaryOp>;
def ARMWrapperPIC : SDNode<"ARMISD::WrapperPIC", SDTIntUnaryOp>;
@@ -245,6 +253,8 @@ def HasV8_2a : Predicate<"Subtarget->hasV8_2aOps()">,
AssemblerPredicate<"HasV8_2aOps", "armv8.2a">;
def HasV8_3a : Predicate<"Subtarget->hasV8_3aOps()">,
AssemblerPredicate<"HasV8_3aOps", "armv8.3a">;
+def HasV8_4a : Predicate<"Subtarget->hasV8_4aOps()">,
+ AssemblerPredicate<"HasV8_4aOps", "armv8.4a">;
def NoVFP : Predicate<"!Subtarget->hasVFP2()">;
def HasVFP2 : Predicate<"Subtarget->hasVFP2()">,
AssemblerPredicate<"FeatureVFP2", "VFP2">;
@@ -259,6 +269,10 @@ def HasFPARMv8 : Predicate<"Subtarget->hasFPARMv8()">,
AssemblerPredicate<"FeatureFPARMv8", "FPARMv8">;
def HasNEON : Predicate<"Subtarget->hasNEON()">,
AssemblerPredicate<"FeatureNEON", "NEON">;
+def HasSHA2 : Predicate<"Subtarget->hasSHA2()">,
+ AssemblerPredicate<"FeatureSHA2", "sha2">;
+def HasAES : Predicate<"Subtarget->hasAES()">,
+ AssemblerPredicate<"FeatureAES", "aes">;
def HasCrypto : Predicate<"Subtarget->hasCrypto()">,
AssemblerPredicate<"FeatureCrypto", "crypto">;
def HasDotProd : Predicate<"Subtarget->hasDotProd()">,
@@ -875,6 +889,16 @@ def bf_inv_mask_imm : Operand<i32>,
let PrintMethod = "printBitfieldInvMaskImmOperand";
let DecoderMethod = "DecodeBitfieldMaskOperand";
let ParserMatchClass = BitfieldAsmOperand;
+ let GISelPredicateCode = [{
+ // There's better methods of implementing this check. IntImmLeaf<> would be
+ // equivalent and have less boilerplate but we need a test for C++
+ // predicates and this one causes new rules to be imported into GlobalISel
+ // without requiring additional features first.
+ const auto &MO = MI.getOperand(1);
+ if (!MO.isCImm())
+ return false;
+ return ARM::isBitFieldInvertedMask(MO.getCImm()->getZExtValue());
+ }];
}
def imm1_32_XFORM: SDNodeXForm<imm, [{
@@ -1996,6 +2020,7 @@ def : InstAlias<"wfi$p", (HINT 3, pred:$p)>, Requires<[IsARM, HasV6K]>;
def : InstAlias<"sev$p", (HINT 4, pred:$p)>, Requires<[IsARM, HasV6K]>;
def : InstAlias<"sevl$p", (HINT 5, pred:$p)>, Requires<[IsARM, HasV8]>;
def : InstAlias<"esb$p", (HINT 16, pred:$p)>, Requires<[IsARM, HasRAS]>;
+def : InstAlias<"csdb$p", (HINT 20, pred:$p)>, Requires<[IsARM, HasV6K]>;
def SEL : AI<(outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm), DPFrm, NoItinerary, "sel",
"\t$Rd, $Rn, $Rm",
@@ -3331,7 +3356,7 @@ defm sysSTM : arm_ldst_mult<"stm", " ^", 0, 1, LdStMulFrm, IIC_iStore_m,
// Move Instructions.
//
-let hasSideEffects = 0 in
+let hasSideEffects = 0, isMoveReg = 1 in
def MOVr : AsI1<0b1101, (outs GPR:$Rd), (ins GPR:$Rm), DPFrm, IIC_iMOVr,
"mov", "\t$Rd, $Rm", []>, UnaryDP, Sched<[WriteALU]> {
bits<4> Rd;
@@ -3904,6 +3929,8 @@ def MVNr : AsI1<0b1111, (outs GPR:$Rd), (ins GPR:$Rm), DPFrm, IIC_iMVNr,
let Inst{11-4} = 0b00000000;
let Inst{15-12} = Rd;
let Inst{3-0} = Rm;
+
+ let Unpredictable{19-16} = 0b1111;
}
def MVNsi : AsI1<0b1111, (outs GPR:$Rd), (ins so_reg_imm:$shift),
DPSoRegImmFrm, IIC_iMVNsr, "mvn", "\t$Rd, $shift",
@@ -3917,10 +3944,12 @@ def MVNsi : AsI1<0b1111, (outs GPR:$Rd), (ins so_reg_imm:$shift),
let Inst{11-5} = shift{11-5};
let Inst{4} = 0;
let Inst{3-0} = shift{3-0};
+
+ let Unpredictable{19-16} = 0b1111;
}
-def MVNsr : AsI1<0b1111, (outs GPR:$Rd), (ins so_reg_reg:$shift),
+def MVNsr : AsI1<0b1111, (outs GPRnopc:$Rd), (ins so_reg_reg:$shift),
DPSoRegRegFrm, IIC_iMVNsr, "mvn", "\t$Rd, $shift",
- [(set GPR:$Rd, (not so_reg_reg:$shift))]>, UnaryDP,
+ [(set GPRnopc:$Rd, (not so_reg_reg:$shift))]>, UnaryDP,
Sched<[WriteALU]> {
bits<4> Rd;
bits<12> shift;
@@ -3932,6 +3961,8 @@ def MVNsr : AsI1<0b1111, (outs GPR:$Rd), (ins so_reg_reg:$shift),
let Inst{6-5} = shift{6-5};
let Inst{4} = 1;
let Inst{3-0} = shift{3-0};
+
+ let Unpredictable{19-16} = 0b1111;
}
let isReMaterializable = 1, isAsCheapAsAMove = 1, isMoveImm = 1 in
def MVNi : AsI1<0b1111, (outs GPR:$Rd), (ins mod_imm:$imm), DPFrm,
@@ -4143,7 +4174,8 @@ def SMMUL : AMul2I <0b0111010, 0b0001, (outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm),
}
def SMMULR : AMul2I <0b0111010, 0b0011, (outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm),
- IIC_iMUL32, "smmulr", "\t$Rd, $Rn, $Rm", []>,
+ IIC_iMUL32, "smmulr", "\t$Rd, $Rn, $Rm",
+ [(set GPR:$Rd, (ARMsmmlar GPR:$Rn, GPR:$Rm, (i32 0)))]>,
Requires<[IsARM, HasV6]>,
Sched<[WriteMUL32, ReadMUL, ReadMUL]> {
let Inst{15-12} = 0b1111;
@@ -4158,7 +4190,8 @@ def SMMLA : AMul2Ia <0b0111010, 0b0001, (outs GPR:$Rd),
def SMMLAR : AMul2Ia <0b0111010, 0b0011, (outs GPR:$Rd),
(ins GPR:$Rn, GPR:$Rm, GPR:$Ra),
- IIC_iMAC32, "smmlar", "\t$Rd, $Rn, $Rm, $Ra", []>,
+ IIC_iMAC32, "smmlar", "\t$Rd, $Rn, $Rm, $Ra",
+ [(set GPR:$Rd, (ARMsmmlar GPR:$Rn, GPR:$Rm, GPR:$Ra))]>,
Requires<[IsARM, HasV6]>,
Sched<[WriteMAC32, ReadMUL, ReadMUL, ReadMAC]>;
@@ -4170,7 +4203,8 @@ def SMMLS : AMul2Ia <0b0111010, 0b1101, (outs GPR:$Rd),
def SMMLSR : AMul2Ia <0b0111010, 0b1111, (outs GPR:$Rd),
(ins GPR:$Rn, GPR:$Rm, GPR:$Ra),
- IIC_iMAC32, "smmlsr", "\t$Rd, $Rn, $Rm, $Ra", []>,
+ IIC_iMAC32, "smmlsr", "\t$Rd, $Rn, $Rm, $Ra",
+ [(set GPR:$Rd, (ARMsmmlsr GPR:$Rn, GPR:$Rm, GPR:$Ra))]>,
Requires<[IsARM, HasV6]>,
Sched<[WriteMAC32, ReadMUL, ReadMUL, ReadMAC]>;
@@ -4785,6 +4819,15 @@ def instsyncb_opt : Operand<i32> {
let DecoderMethod = "DecodeInstSyncBarrierOption";
}
+def TraceSyncBarrierOptOperand : AsmOperandClass {
+ let Name = "TraceSyncBarrierOpt";
+ let ParserMethod = "parseTraceSyncBarrierOptOperand";
+}
+def tsb_opt : Operand<i32> {
+ let PrintMethod = "printTraceSyncBOption";
+ let ParserMatchClass = TraceSyncBarrierOptOperand;
+}
+
// Memory barriers protect the atomic sequences
let hasSideEffects = 1 in {
def DMB : AInoP<(outs), (ins memb_opt:$opt), MiscFrm, NoItinerary,
@@ -4811,6 +4854,13 @@ def ISB : AInoP<(outs), (ins instsyncb_opt:$opt), MiscFrm, NoItinerary,
let Inst{31-4} = 0xf57ff06;
let Inst{3-0} = opt;
}
+
+let hasNoSchedulingInfo = 1 in
+def TSB : AInoP<(outs), (ins tsb_opt:$opt), MiscFrm, NoItinerary,
+ "tsb", "\t$opt", []>, Requires<[IsARM, HasV8_4a]> {
+ let Inst{31-0} = 0xe320f012;
+}
+
}
let usesCustomInserter = 1, Defs = [CPSR] in {
diff --git a/lib/Target/ARM/ARMInstrNEON.td b/lib/Target/ARM/ARMInstrNEON.td
index cd67dded5853..4525eec8da03 100644
--- a/lib/Target/ARM/ARMInstrNEON.td
+++ b/lib/Target/ARM/ARMInstrNEON.td
@@ -48,46 +48,28 @@ def nImmVMOVI32 : Operand<i32> {
let ParserMatchClass = nImmVMOVI32AsmOperand;
}
-def nImmVMOVI16AsmOperandByteReplicate :
- AsmOperandClass {
- let Name = "NEONi16vmovByteReplicate";
- let PredicateMethod = "isNEONi16ByteReplicate";
- let RenderMethod = "addNEONvmovByteReplicateOperands";
-}
-def nImmVMOVI32AsmOperandByteReplicate :
- AsmOperandClass {
- let Name = "NEONi32vmovByteReplicate";
- let PredicateMethod = "isNEONi32ByteReplicate";
- let RenderMethod = "addNEONvmovByteReplicateOperands";
-}
-def nImmVMVNI16AsmOperandByteReplicate :
- AsmOperandClass {
- let Name = "NEONi16invByteReplicate";
- let PredicateMethod = "isNEONi16ByteReplicate";
- let RenderMethod = "addNEONinvByteReplicateOperands";
-}
-def nImmVMVNI32AsmOperandByteReplicate :
- AsmOperandClass {
- let Name = "NEONi32invByteReplicate";
- let PredicateMethod = "isNEONi32ByteReplicate";
- let RenderMethod = "addNEONinvByteReplicateOperands";
+class nImmVMOVIAsmOperandReplicate<ValueType From, ValueType To>
+ : AsmOperandClass {
+ let Name = "NEONi" # To.Size # "vmovi" # From.Size # "Replicate";
+ let PredicateMethod = "isNEONmovReplicate<" # From.Size # ", " # To.Size # ">";
+ let RenderMethod = "addNEONvmovi" # From.Size # "ReplicateOperands";
}
-def nImmVMOVI16ByteReplicate : Operand<i32> {
- let PrintMethod = "printNEONModImmOperand";
- let ParserMatchClass = nImmVMOVI16AsmOperandByteReplicate;
-}
-def nImmVMOVI32ByteReplicate : Operand<i32> {
- let PrintMethod = "printNEONModImmOperand";
- let ParserMatchClass = nImmVMOVI32AsmOperandByteReplicate;
+class nImmVINVIAsmOperandReplicate<ValueType From, ValueType To>
+ : AsmOperandClass {
+ let Name = "NEONi" # To.Size # "invi" # From.Size # "Replicate";
+ let PredicateMethod = "isNEONinvReplicate<" # From.Size # ", " # To.Size # ">";
+ let RenderMethod = "addNEONinvi" # From.Size # "ReplicateOperands";
}
-def nImmVMVNI16ByteReplicate : Operand<i32> {
+
+class nImmVMOVIReplicate<ValueType From, ValueType To> : Operand<i32> {
let PrintMethod = "printNEONModImmOperand";
- let ParserMatchClass = nImmVMVNI16AsmOperandByteReplicate;
+ let ParserMatchClass = nImmVMOVIAsmOperandReplicate<From, To>;
}
-def nImmVMVNI32ByteReplicate : Operand<i32> {
+
+class nImmVINVIReplicate<ValueType From, ValueType To> : Operand<i32> {
let PrintMethod = "printNEONModImmOperand";
- let ParserMatchClass = nImmVMVNI32AsmOperandByteReplicate;
+ let ParserMatchClass = nImmVINVIAsmOperandReplicate<From, To>;
}
def nImmVMOVI32NegAsmOperand : AsmOperandClass { let Name = "NEONi32vmovNeg"; }
@@ -227,7 +209,7 @@ def VecListDPairSpacedAllLanesAsmOperand : AsmOperandClass {
let ParserMethod = "parseVectorList";
let RenderMethod = "addVecListOperands";
}
-def VecListDPairSpacedAllLanes : RegisterOperand<DPair,
+def VecListDPairSpacedAllLanes : RegisterOperand<DPairSpc,
"printVectorListTwoSpacedAllLanes"> {
let ParserMatchClass = VecListDPairSpacedAllLanesAsmOperand;
}
@@ -788,10 +770,22 @@ defm VLD1d16Twb : VLD1D3WB<{0,1,0,?}, "16", addrmode6align64>;
defm VLD1d32Twb : VLD1D3WB<{1,0,0,?}, "32", addrmode6align64>;
defm VLD1d64Twb : VLD1D3WB<{1,1,0,?}, "64", addrmode6align64>;
+def VLD1d8TPseudo : VLDQQPseudo<IIC_VLD1x3>, Sched<[WriteVLD3]>;
+def VLD1d16TPseudo : VLDQQPseudo<IIC_VLD1x3>, Sched<[WriteVLD3]>;
+def VLD1d32TPseudo : VLDQQPseudo<IIC_VLD1x3>, Sched<[WriteVLD3]>;
def VLD1d64TPseudo : VLDQQPseudo<IIC_VLD1x3>, Sched<[WriteVLD3]>;
def VLD1d64TPseudoWB_fixed : VLDQQWBfixedPseudo<IIC_VLD1x3>, Sched<[WriteVLD3]>;
def VLD1d64TPseudoWB_register : VLDQQWBregisterPseudo<IIC_VLD1x3>, Sched<[WriteVLD3]>;
+def VLD1q8HighTPseudo : VLDQQQQPseudo<IIC_VLD1x3>, Sched<[WriteVLD3]>;
+def VLD1q8LowTPseudo_UPD : VLDQQQQWBPseudo<IIC_VLD1x3>, Sched<[WriteVLD3]>;
+def VLD1q16HighTPseudo : VLDQQQQPseudo<IIC_VLD1x3>, Sched<[WriteVLD3]>;
+def VLD1q16LowTPseudo_UPD : VLDQQQQWBPseudo<IIC_VLD1x3>, Sched<[WriteVLD3]>;
+def VLD1q32HighTPseudo : VLDQQQQPseudo<IIC_VLD1x3>, Sched<[WriteVLD3]>;
+def VLD1q32LowTPseudo_UPD : VLDQQQQWBPseudo<IIC_VLD1x3>, Sched<[WriteVLD3]>;
+def VLD1q64HighTPseudo : VLDQQQQPseudo<IIC_VLD1x3>, Sched<[WriteVLD3]>;
+def VLD1q64LowTPseudo_UPD : VLDQQQQWBPseudo<IIC_VLD1x3>, Sched<[WriteVLD3]>;
+
// ...with 4 registers
class VLD1D4<bits<4> op7_4, string Dt, Operand AddrMode>
: NLdSt<0, 0b10, 0b0010, op7_4, (outs VecListFourD:$Vd),
@@ -829,10 +823,22 @@ defm VLD1d16Qwb : VLD1D4WB<{0,1,?,?}, "16", addrmode6align64or128or256>;
defm VLD1d32Qwb : VLD1D4WB<{1,0,?,?}, "32", addrmode6align64or128or256>;
defm VLD1d64Qwb : VLD1D4WB<{1,1,?,?}, "64", addrmode6align64or128or256>;
+def VLD1d8QPseudo : VLDQQPseudo<IIC_VLD1x4>, Sched<[WriteVLD4]>;
+def VLD1d16QPseudo : VLDQQPseudo<IIC_VLD1x4>, Sched<[WriteVLD4]>;
+def VLD1d32QPseudo : VLDQQPseudo<IIC_VLD1x4>, Sched<[WriteVLD4]>;
def VLD1d64QPseudo : VLDQQPseudo<IIC_VLD1x4>, Sched<[WriteVLD4]>;
def VLD1d64QPseudoWB_fixed : VLDQQWBfixedPseudo<IIC_VLD1x4>, Sched<[WriteVLD4]>;
def VLD1d64QPseudoWB_register : VLDQQWBregisterPseudo<IIC_VLD1x4>, Sched<[WriteVLD4]>;
+def VLD1q8LowQPseudo_UPD : VLDQQQQWBPseudo<IIC_VLD1x4>, Sched<[WriteVLD4]>;
+def VLD1q8HighQPseudo : VLDQQQQPseudo<IIC_VLD1x4>, Sched<[WriteVLD4]>;
+def VLD1q16LowQPseudo_UPD : VLDQQQQWBPseudo<IIC_VLD1x4>, Sched<[WriteVLD4]>;
+def VLD1q16HighQPseudo : VLDQQQQPseudo<IIC_VLD1x4>, Sched<[WriteVLD4]>;
+def VLD1q32LowQPseudo_UPD : VLDQQQQWBPseudo<IIC_VLD1x4>, Sched<[WriteVLD4]>;
+def VLD1q32HighQPseudo : VLDQQQQPseudo<IIC_VLD1x4>, Sched<[WriteVLD4]>;
+def VLD1q64LowQPseudo_UPD : VLDQQQQWBPseudo<IIC_VLD1x4>, Sched<[WriteVLD4]>;
+def VLD1q64HighQPseudo : VLDQQQQPseudo<IIC_VLD1x4>, Sched<[WriteVLD4]>;
+
// VLD2 : Vector Load (multiple 2-element structures)
class VLD2<bits<4> op11_8, bits<4> op7_4, string Dt, RegisterOperand VdTy,
InstrItinClass itin, Operand AddrMode>
@@ -1512,6 +1518,13 @@ def VLD2DUPd16x2 : VLD2DUP<{0,1,1,?}, "16", VecListDPairSpacedAllLanes,
def VLD2DUPd32x2 : VLD2DUP<{1,0,1,?}, "32", VecListDPairSpacedAllLanes,
addrmode6dupalign64>;
+def VLD2DUPq8EvenPseudo : VLDQQPseudo<IIC_VLD2dup>, Sched<[WriteVLD2]>;
+def VLD2DUPq8OddPseudo : VLDQQPseudo<IIC_VLD2dup>, Sched<[WriteVLD2]>;
+def VLD2DUPq16EvenPseudo : VLDQQPseudo<IIC_VLD2dup>, Sched<[WriteVLD2]>;
+def VLD2DUPq16OddPseudo : VLDQQPseudo<IIC_VLD2dup>, Sched<[WriteVLD2]>;
+def VLD2DUPq32EvenPseudo : VLDQQPseudo<IIC_VLD2dup>, Sched<[WriteVLD2]>;
+def VLD2DUPq32OddPseudo : VLDQQPseudo<IIC_VLD2dup>, Sched<[WriteVLD2]>;
+
// ...with address register writeback:
multiclass VLD2DUPWB<bits<4> op7_4, string Dt, RegisterOperand VdTy,
Operand AddrMode> {
@@ -1572,6 +1585,13 @@ def VLD3DUPq8 : VLD3DUP<{0,0,1,?}, "8">;
def VLD3DUPq16 : VLD3DUP<{0,1,1,?}, "16">;
def VLD3DUPq32 : VLD3DUP<{1,0,1,?}, "32">;
+def VLD3DUPq8EvenPseudo : VLDQQQQPseudo<IIC_VLD3dup>, Sched<[WriteVLD2]>;
+def VLD3DUPq8OddPseudo : VLDQQQQPseudo<IIC_VLD3dup>, Sched<[WriteVLD2]>;
+def VLD3DUPq16EvenPseudo : VLDQQQQPseudo<IIC_VLD3dup>, Sched<[WriteVLD2]>;
+def VLD3DUPq16OddPseudo : VLDQQQQPseudo<IIC_VLD3dup>, Sched<[WriteVLD2]>;
+def VLD3DUPq32EvenPseudo : VLDQQQQPseudo<IIC_VLD3dup>, Sched<[WriteVLD2]>;
+def VLD3DUPq32OddPseudo : VLDQQQQPseudo<IIC_VLD3dup>, Sched<[WriteVLD2]>;
+
// ...with address register writeback:
class VLD3DUPWB<bits<4> op7_4, string Dt, Operand AddrMode>
: NLdSt<1, 0b10, 0b1110, op7_4, (outs DPR:$Vd, DPR:$dst2, DPR:$dst3, GPR:$wb),
@@ -1618,6 +1638,13 @@ def VLD4DUPq8 : VLD4DUP<{0,0,1,?}, "8">;
def VLD4DUPq16 : VLD4DUP<{0,1,1,?}, "16">;
def VLD4DUPq32 : VLD4DUP<{1,?,1,?}, "32"> { let Inst{6} = Rn{5}; }
+def VLD4DUPq8EvenPseudo : VLDQQQQPseudo<IIC_VLD4dup>, Sched<[WriteVLD2]>;
+def VLD4DUPq8OddPseudo : VLDQQQQPseudo<IIC_VLD4dup>, Sched<[WriteVLD2]>;
+def VLD4DUPq16EvenPseudo : VLDQQQQPseudo<IIC_VLD4dup>, Sched<[WriteVLD2]>;
+def VLD4DUPq16OddPseudo : VLDQQQQPseudo<IIC_VLD4dup>, Sched<[WriteVLD2]>;
+def VLD4DUPq32EvenPseudo : VLDQQQQPseudo<IIC_VLD4dup>, Sched<[WriteVLD2]>;
+def VLD4DUPq32OddPseudo : VLDQQQQPseudo<IIC_VLD4dup>, Sched<[WriteVLD2]>;
+
// ...with address register writeback:
class VLD4DUPWB<bits<4> op7_4, string Dt>
: NLdSt<1, 0b10, 0b1111, op7_4,
@@ -1795,10 +1822,22 @@ defm VST1d16Twb : VST1D3WB<{0,1,0,?}, "16", addrmode6align64>;
defm VST1d32Twb : VST1D3WB<{1,0,0,?}, "32", addrmode6align64>;
defm VST1d64Twb : VST1D3WB<{1,1,0,?}, "64", addrmode6align64>;
+def VST1d8TPseudo : VSTQQPseudo<IIC_VST1x3>, Sched<[WriteVST3]>;
+def VST1d16TPseudo : VSTQQPseudo<IIC_VST1x3>, Sched<[WriteVST3]>;
+def VST1d32TPseudo : VSTQQPseudo<IIC_VST1x3>, Sched<[WriteVST3]>;
def VST1d64TPseudo : VSTQQPseudo<IIC_VST1x3>, Sched<[WriteVST3]>;
def VST1d64TPseudoWB_fixed : VSTQQWBfixedPseudo<IIC_VST1x3u>, Sched<[WriteVST3]>;
def VST1d64TPseudoWB_register : VSTQQWBPseudo<IIC_VST1x3u>, Sched<[WriteVST3]>;
+def VST1q8HighTPseudo : VSTQQQQPseudo<IIC_VST1x3>, Sched<[WriteVST3]>;
+def VST1q8LowTPseudo_UPD : VSTQQQQWBPseudo<IIC_VST1x3>, Sched<[WriteVST3]>;
+def VST1q16HighTPseudo : VSTQQQQPseudo<IIC_VST1x3>, Sched<[WriteVST3]>;
+def VST1q16LowTPseudo_UPD : VSTQQQQWBPseudo<IIC_VST1x3>, Sched<[WriteVST3]>;
+def VST1q32HighTPseudo : VSTQQQQPseudo<IIC_VST1x3>, Sched<[WriteVST3]>;
+def VST1q32LowTPseudo_UPD : VSTQQQQWBPseudo<IIC_VST1x3>, Sched<[WriteVST3]>;
+def VST1q64HighTPseudo : VSTQQQQPseudo<IIC_VST1x3>, Sched<[WriteVST3]>;
+def VST1q64LowTPseudo_UPD : VSTQQQQWBPseudo<IIC_VST1x3>, Sched<[WriteVST3]>;
+
// ...with 4 registers
class VST1D4<bits<4> op7_4, string Dt, Operand AddrMode>
: NLdSt<0, 0b00, 0b0010, op7_4, (outs),
@@ -1838,10 +1877,22 @@ defm VST1d16Qwb : VST1D4WB<{0,1,?,?}, "16", addrmode6align64or128or256>;
defm VST1d32Qwb : VST1D4WB<{1,0,?,?}, "32", addrmode6align64or128or256>;
defm VST1d64Qwb : VST1D4WB<{1,1,?,?}, "64", addrmode6align64or128or256>;
+def VST1d8QPseudo : VSTQQPseudo<IIC_VST1x4>, Sched<[WriteVST4]>;
+def VST1d16QPseudo : VSTQQPseudo<IIC_VST1x4>, Sched<[WriteVST4]>;
+def VST1d32QPseudo : VSTQQPseudo<IIC_VST1x4>, Sched<[WriteVST4]>;
def VST1d64QPseudo : VSTQQPseudo<IIC_VST1x4>, Sched<[WriteVST4]>;
def VST1d64QPseudoWB_fixed : VSTQQWBfixedPseudo<IIC_VST1x4u>, Sched<[WriteVST4]>;
def VST1d64QPseudoWB_register : VSTQQWBPseudo<IIC_VST1x4u>, Sched<[WriteVST4]>;
+def VST1q8HighQPseudo : VSTQQQQPseudo<IIC_VST1x4>, Sched<[WriteVST4]>;
+def VST1q8LowQPseudo_UPD : VSTQQQQWBPseudo<IIC_VST1x4>, Sched<[WriteVST4]>;
+def VST1q16HighQPseudo : VSTQQQQPseudo<IIC_VST1x4>, Sched<[WriteVST4]>;
+def VST1q16LowQPseudo_UPD : VSTQQQQWBPseudo<IIC_VST1x4>, Sched<[WriteVST4]>;
+def VST1q32HighQPseudo : VSTQQQQPseudo<IIC_VST1x4>, Sched<[WriteVST4]>;
+def VST1q32LowQPseudo_UPD : VSTQQQQWBPseudo<IIC_VST1x4>, Sched<[WriteVST4]>;
+def VST1q64HighQPseudo : VSTQQQQPseudo<IIC_VST1x4>, Sched<[WriteVST4]>;
+def VST1q64LowQPseudo_UPD : VSTQQQQWBPseudo<IIC_VST1x4>, Sched<[WriteVST4]>;
+
// VST2 : Vector Store (multiple 2-element structures)
class VST2<bits<4> op11_8, bits<4> op7_4, string Dt, RegisterOperand VdTy,
InstrItinClass itin, Operand AddrMode>
@@ -4700,37 +4751,59 @@ def : Pat<(v4f32 (fma (fneg QPR:$Vn), QPR:$Vm, QPR:$src1)),
// We put them in the VFPV8 decoder namespace because the ARM and Thumb
// encodings are the same and thus no further bit twiddling is necessary
// in the disassembler.
-let Predicates = [HasDotProd], DecoderNamespace = "VFPV8" in {
+class VDOT<bit op6, bit op4, RegisterClass RegTy, string Asm, string AsmTy,
+ ValueType AccumTy, ValueType InputTy,
+ SDPatternOperator OpNode> :
+ N3Vnp<0b11000, 0b10, 0b1101, op6, op4, (outs RegTy:$dst),
+ (ins RegTy:$Vd, RegTy:$Vn, RegTy:$Vm), N3RegFrm, IIC_VDOTPROD,
+ Asm, AsmTy,
+ [(set (AccumTy RegTy:$dst),
+ (OpNode (AccumTy RegTy:$Vd),
+ (InputTy RegTy:$Vn),
+ (InputTy RegTy:$Vm)))]> {
+ let Predicates = [HasDotProd];
+ let DecoderNamespace = "VFPV8";
+ let Constraints = "$dst = $Vd";
+}
-def VUDOTD : N3Vnp<0b11000, 0b10, 0b1101, 0b0, 0b1,
- (outs DPR:$Vd), (ins DPR:$Vn, DPR:$Vm),
- N3RegFrm, IIC_VDOTPROD, "vudot", "u8", []>;
-def VSDOTD : N3Vnp<0b11000, 0b10, 0b1101, 0b0, 0b0,
- (outs DPR:$Vd), (ins DPR:$Vn, DPR:$Vm),
- N3RegFrm, IIC_VDOTPROD, "vsdot", "s8", []>;
-def VUDOTQ : N3Vnp<0b11000, 0b10, 0b1101, 0b1, 0b1,
- (outs QPR:$Vd), (ins QPR:$Vn, QPR:$Vm),
- N3RegFrm, IIC_VDOTPROD, "vudot", "u8", []>;
-def VSDOTQ : N3Vnp<0b11000, 0b10, 0b1101, 0b1, 0b0,
- (outs QPR:$Vd), (ins QPR:$Vn, QPR:$Vm),
- N3RegFrm, IIC_VDOTPROD, "vsdot", "s8", []>;
+def VUDOTD : VDOT<0, 1, DPR, "vudot", "u8", v2i32, v8i8, int_arm_neon_udot>;
+def VSDOTD : VDOT<0, 0, DPR, "vsdot", "s8", v2i32, v8i8, int_arm_neon_sdot>;
+def VUDOTQ : VDOT<1, 1, QPR, "vudot", "u8", v4i32, v16i8, int_arm_neon_udot>;
+def VSDOTQ : VDOT<1, 0, QPR, "vsdot", "s8", v4i32, v16i8, int_arm_neon_sdot>;
// Indexed dot product instructions:
-class DOTI<string opc, string dt, bit Q, bit U, RegisterClass Ty> :
- N3Vnp<0b11100, 0b10, 0b1101, Q, U,
- (outs Ty:$Vd), (ins Ty:$Vn, DPR_VFP2:$Vm, VectorIndex32:$lane),
- N3RegFrm, IIC_VDOTPROD, opc, dt, []> {
- bit lane;
- let Inst{5} = lane;
- let AsmString = !strconcat(opc, ".", dt, "\t$Vd, $Vn, $Vm$lane");
+multiclass DOTI<string opc, string dt, bit Q, bit U, RegisterClass Ty,
+ ValueType AccumType, ValueType InputType, SDPatternOperator OpNode,
+ dag RHS> {
+ def "" : N3Vnp<0b11100, 0b10, 0b1101, Q, U, (outs Ty:$dst),
+ (ins Ty:$Vd, Ty:$Vn, DPR_VFP2:$Vm, VectorIndex32:$lane),
+ N3RegFrm, IIC_VDOTPROD, opc, dt, []> {
+ bit lane;
+ let Inst{5} = lane;
+ let AsmString = !strconcat(opc, ".", dt, "\t$Vd, $Vn, $Vm$lane");
+ let Constraints = "$dst = $Vd";
+ let Predicates = [HasDotProd];
+ let DecoderNamespace = "VFPV8";
+ }
+
+ def : Pat<
+ (AccumType (OpNode (AccumType Ty:$Vd),
+ (InputType Ty:$Vn),
+ (InputType (bitconvert (AccumType
+ (NEONvduplane (AccumType Ty:$Vm),
+ VectorIndex32:$lane)))))),
+ (!cast<Instruction>(NAME) Ty:$Vd, Ty:$Vn, RHS, VectorIndex32:$lane)>;
}
-def VUDOTDI : DOTI<"vudot", "u8", 0b0, 0b1, DPR>;
-def VSDOTDI : DOTI<"vsdot", "s8", 0b0, 0b0, DPR>;
-def VUDOTQI : DOTI<"vudot", "u8", 0b1, 0b1, QPR>;
-def VSDOTQI : DOTI<"vsdot", "s8", 0b1, 0b0, QPR>;
+defm VUDOTDI : DOTI<"vudot", "u8", 0b0, 0b1, DPR, v2i32, v8i8,
+ int_arm_neon_udot, (v2i32 DPR_VFP2:$Vm)>;
+defm VSDOTDI : DOTI<"vsdot", "s8", 0b0, 0b0, DPR, v2i32, v8i8,
+ int_arm_neon_sdot, (v2i32 DPR_VFP2:$Vm)>;
+defm VUDOTQI : DOTI<"vudot", "u8", 0b1, 0b1, QPR, v4i32, v16i8,
+ int_arm_neon_udot, (EXTRACT_SUBREG QPR:$Vm, dsub_0)>;
+defm VSDOTQI : DOTI<"vsdot", "s8", 0b1, 0b0, QPR, v4i32, v16i8,
+ int_arm_neon_sdot, (EXTRACT_SUBREG QPR:$Vm, dsub_0)>;
-} // HasDotProd
// ARMv8.3 complex operations
class BaseN3VCP8ComplexTied<bit op21, bit op4, bit s, bit q,
@@ -5340,23 +5413,19 @@ defm VABDLs : N3VLIntExt_QHS<0,1,0b0111,0, IIC_VSUBi4Q,
defm VABDLu : N3VLIntExt_QHS<1,1,0b0111,0, IIC_VSUBi4Q,
"vabdl", "u", int_arm_neon_vabdu, zext, 1>;
+def : Pat<(v8i16 (abs (sub (zext (v8i8 DPR:$opA)), (zext (v8i8 DPR:$opB))))),
+ (VABDLuv8i16 DPR:$opA, DPR:$opB)>;
+def : Pat<(v4i32 (abs (sub (zext (v4i16 DPR:$opA)), (zext (v4i16 DPR:$opB))))),
+ (VABDLuv4i32 DPR:$opA, DPR:$opB)>;
+
+// ISD::ABS is not legal for v2i64, so VABDL needs to be matched from the
+// shift/xor pattern for ABS.
+
def abd_shr :
PatFrag<(ops node:$in1, node:$in2, node:$shift),
(NEONvshrs (sub (zext node:$in1),
(zext node:$in2)), (i32 $shift))>;
-def : Pat<(xor (v4i32 (bitconvert (v8i16 (abd_shr (v8i8 DPR:$opA), (v8i8 DPR:$opB), 15)))),
- (v4i32 (bitconvert (v8i16 (add (sub (zext (v8i8 DPR:$opA)),
- (zext (v8i8 DPR:$opB))),
- (v8i16 (abd_shr (v8i8 DPR:$opA), (v8i8 DPR:$opB), 15))))))),
- (VABDLuv8i16 DPR:$opA, DPR:$opB)>;
-
-def : Pat<(xor (v4i32 (abd_shr (v4i16 DPR:$opA), (v4i16 DPR:$opB), 31)),
- (v4i32 (add (sub (zext (v4i16 DPR:$opA)),
- (zext (v4i16 DPR:$opB))),
- (abd_shr (v4i16 DPR:$opA), (v4i16 DPR:$opB), 31)))),
- (VABDLuv4i32 DPR:$opA, DPR:$opB)>;
-
def : Pat<(xor (v4i32 (bitconvert (v2i64 (abd_shr (v2i32 DPR:$opA), (v2i32 DPR:$opB), 63)))),
(v4i32 (bitconvert (v2i64 (add (sub (zext (v2i32 DPR:$opA)),
(zext (v2i32 DPR:$opB))),
@@ -5933,34 +6002,57 @@ def VMOVv4f32 : N1ModImm<1, 0b000, 0b1111, 0, 1, 0, 1, (outs QPR:$Vd),
} // isReMaterializable, isAsCheapAsAMove
// Add support for bytes replication feature, so it could be GAS compatible.
-// E.g. instructions below:
-// "vmov.i32 d0, 0xffffffff"
-// "vmov.i32 d0, 0xabababab"
-// "vmov.i16 d0, 0xabab"
-// are incorrect, but we could deal with such cases.
-// For last two instructions, for example, it should emit:
-// "vmov.i8 d0, 0xab"
-def : NEONInstAlias<"vmov${p}.i16 $Vd, $Vm",
- (VMOVv8i8 DPR:$Vd, nImmVMOVI16ByteReplicate:$Vm, pred:$p)>;
-def : NEONInstAlias<"vmov${p}.i32 $Vd, $Vm",
- (VMOVv8i8 DPR:$Vd, nImmVMOVI32ByteReplicate:$Vm, pred:$p)>;
-def : NEONInstAlias<"vmov${p}.i16 $Vd, $Vm",
- (VMOVv16i8 QPR:$Vd, nImmVMOVI16ByteReplicate:$Vm, pred:$p)>;
-def : NEONInstAlias<"vmov${p}.i32 $Vd, $Vm",
- (VMOVv16i8 QPR:$Vd, nImmVMOVI32ByteReplicate:$Vm, pred:$p)>;
+multiclass NEONImmReplicateI8InstAlias<ValueType To> {
+ // E.g. instructions below:
+ // "vmov.i32 d0, #0xffffffff"
+ // "vmov.i32 d0, #0xabababab"
+ // "vmov.i16 d0, #0xabab"
+ // are incorrect, but we could deal with such cases.
+ // For last two instructions, for example, it should emit:
+ // "vmov.i8 d0, #0xab"
+ def : NEONInstAlias<"vmov${p}.i" # To.Size # " $Vd, $Vm",
+ (VMOVv8i8 DPR:$Vd, nImmVMOVIReplicate<i8, To>:$Vm, pred:$p)>;
+ def : NEONInstAlias<"vmov${p}.i" # To.Size # " $Vd, $Vm",
+ (VMOVv16i8 QPR:$Vd, nImmVMOVIReplicate<i8, To>:$Vm, pred:$p)>;
+ // Also add same support for VMVN instructions. So instruction:
+ // "vmvn.i32 d0, #0xabababab"
+ // actually means:
+ // "vmov.i8 d0, #0x54"
+ def : NEONInstAlias<"vmvn${p}.i" # To.Size # " $Vd, $Vm",
+ (VMOVv8i8 DPR:$Vd, nImmVINVIReplicate<i8, To>:$Vm, pred:$p)>;
+ def : NEONInstAlias<"vmvn${p}.i" # To.Size # " $Vd, $Vm",
+ (VMOVv16i8 QPR:$Vd, nImmVINVIReplicate<i8, To>:$Vm, pred:$p)>;
+}
-// Also add same support for VMVN instructions. So instruction:
-// "vmvn.i32 d0, 0xabababab"
-// actually means:
-// "vmov.i8 d0, 0x54"
-def : NEONInstAlias<"vmvn${p}.i16 $Vd, $Vm",
- (VMOVv8i8 DPR:$Vd, nImmVMVNI16ByteReplicate:$Vm, pred:$p)>;
-def : NEONInstAlias<"vmvn${p}.i32 $Vd, $Vm",
- (VMOVv8i8 DPR:$Vd, nImmVMVNI32ByteReplicate:$Vm, pred:$p)>;
-def : NEONInstAlias<"vmvn${p}.i16 $Vd, $Vm",
- (VMOVv16i8 QPR:$Vd, nImmVMVNI16ByteReplicate:$Vm, pred:$p)>;
-def : NEONInstAlias<"vmvn${p}.i32 $Vd, $Vm",
- (VMOVv16i8 QPR:$Vd, nImmVMVNI32ByteReplicate:$Vm, pred:$p)>;
+defm : NEONImmReplicateI8InstAlias<i16>;
+defm : NEONImmReplicateI8InstAlias<i32>;
+defm : NEONImmReplicateI8InstAlias<i64>;
+
+// Similar to above for types other than i8, e.g.:
+// "vmov.i32 d0, #0xab00ab00" -> "vmov.i16 d0, #0xab00"
+// "vmvn.i64 q0, #0xab000000ab000000" -> "vmvn.i32 q0, #0xab000000"
+// In this case we do not canonicalize VMVN to VMOV
+multiclass NEONImmReplicateInstAlias<ValueType From, NeonI V8, NeonI V16,
+ NeonI NV8, NeonI NV16, ValueType To> {
+ def : NEONInstAlias<"vmov${p}.i" # To.Size # " $Vd, $Vm",
+ (V8 DPR:$Vd, nImmVMOVIReplicate<From, To>:$Vm, pred:$p)>;
+ def : NEONInstAlias<"vmov${p}.i" # To.Size # " $Vd, $Vm",
+ (V16 QPR:$Vd, nImmVMOVIReplicate<From, To>:$Vm, pred:$p)>;
+ def : NEONInstAlias<"vmvn${p}.i" # To.Size # " $Vd, $Vm",
+ (NV8 DPR:$Vd, nImmVMOVIReplicate<From, To>:$Vm, pred:$p)>;
+ def : NEONInstAlias<"vmvn${p}.i" # To.Size # " $Vd, $Vm",
+ (NV16 QPR:$Vd, nImmVMOVIReplicate<From, To>:$Vm, pred:$p)>;
+}
+
+defm : NEONImmReplicateInstAlias<i16, VMOVv4i16, VMOVv8i16,
+ VMVNv4i16, VMVNv8i16, i32>;
+defm : NEONImmReplicateInstAlias<i16, VMOVv4i16, VMOVv8i16,
+ VMVNv4i16, VMVNv8i16, i64>;
+defm : NEONImmReplicateInstAlias<i32, VMOVv2i32, VMOVv4i32,
+ VMVNv2i32, VMVNv4i32, i64>;
+// TODO: add "VMOV <-> VMVN" conversion for cases like
+// "vmov.i32 d0, #0xffaaffaa" -> "vmvn.i16 d0, #0x55"
+// "vmvn.i32 d0, #0xaaffaaff" -> "vmov.i16 d0, #0xff00"
// On some CPUs the two instructions "vmov.i32 dD, #0" and "vmov.i32 qD, #0"
// require zero cycles to execute so they should be used wherever possible for
@@ -6865,6 +6957,17 @@ class N3VSPat<SDNode OpNode, NeonI Inst>
(v2f32 (COPY_TO_REGCLASS (v2f32 (IMPLICIT_DEF)), DPR_VFP2)),
SPR:$b, ssub_0)), DPR_VFP2)), ssub_0)>;
+class N3VSPatFP16<SDNode OpNode, NeonI Inst>
+ : NEONFPPat<(f16 (OpNode HPR:$a, HPR:$b)),
+ (EXTRACT_SUBREG
+ (v4f16 (COPY_TO_REGCLASS (Inst
+ (INSERT_SUBREG
+ (v4f16 (COPY_TO_REGCLASS (v4f16 (IMPLICIT_DEF)), DPR_VFP2)),
+ HPR:$a, ssub_0),
+ (INSERT_SUBREG
+ (v4f16 (COPY_TO_REGCLASS (v4f16 (IMPLICIT_DEF)), DPR_VFP2)),
+ HPR:$b, ssub_0)), DPR_VFP2)), ssub_0)>;
+
class N3VSMulOpPat<SDNode MulNode, SDNode OpNode, NeonI Inst>
: NEONFPPat<(f32 (OpNode SPR:$acc, (f32 (MulNode SPR:$a, SPR:$b)))),
(EXTRACT_SUBREG
@@ -6907,6 +7010,8 @@ def : N3VSMulOpPat<fmul, fsub, VFMSfd>,
Requires<[HasVFP4, UseNEONForFP, UseFusedMAC]>;
def : N2VSPat<fabs, VABSfd>;
def : N2VSPat<fneg, VNEGfd>;
+def : N3VSPatFP16<fmaxnan, VMAXhd>, Requires<[HasFullFP16]>;
+def : N3VSPatFP16<fminnan, VMINhd>, Requires<[HasFullFP16]>;
def : N3VSPat<fmaxnan, VMAXfd>, Requires<[HasNEON]>;
def : N3VSPat<fminnan, VMINfd>, Requires<[HasNEON]>;
def : NVCVTFIPat<fp_to_sint, VCVTf2sd>;
@@ -6930,6 +7035,9 @@ def : VFPPat<(f64 (uint_to_fp (extractelt (v4i32 QPR:$src), imm:$lane))),
def : Pat<(f32 (bitconvert GPR:$a)),
(EXTRACT_SUBREG (VMOVDRR GPR:$a, GPR:$a), ssub_0)>,
Requires<[HasNEON, DontUseVMOVSR]>;
+def : Pat<(arm_vmovsr GPR:$a),
+ (EXTRACT_SUBREG (VMOVDRR GPR:$a, GPR:$a), ssub_0)>,
+ Requires<[HasNEON, DontUseVMOVSR]>;
//===----------------------------------------------------------------------===//
// Non-Instruction Patterns
@@ -6966,9 +7074,11 @@ def : Pat<(f64 (bitconvert (v1i64 DPR:$src))), (f64 DPR:$src)>;
let Predicates = [IsLE] in {
def : Pat<(f64 (bitconvert (v2i32 DPR:$src))), (f64 DPR:$src)>;
def : Pat<(f64 (bitconvert (v4i16 DPR:$src))), (f64 DPR:$src)>;
+ def : Pat<(f64 (bitconvert (v4f16 DPR:$src))), (f64 DPR:$src)>;
def : Pat<(f64 (bitconvert (v8i8 DPR:$src))), (f64 DPR:$src)>;
def : Pat<(f64 (bitconvert (v2f32 DPR:$src))), (f64 DPR:$src)>;
def : Pat<(v2f32 (bitconvert (f64 DPR:$src))), (v2f32 DPR:$src)>;
+ def : Pat<(v4f16 (bitconvert (f64 DPR:$src))), (v4f16 DPR:$src)>;
def : Pat<(v2f32 (bitconvert (v1i64 DPR:$src))), (v2f32 DPR:$src)>;
}
def : Pat<(v2f32 (bitconvert (v2i32 DPR:$src))), (v2f32 DPR:$src)>;
@@ -6997,6 +7107,7 @@ let Predicates = [IsLE] in {
def : Pat<(v8i16 (bitconvert (v16i8 QPR:$src))), (v8i16 QPR:$src)>;
def : Pat<(v8i16 (bitconvert (v2f64 QPR:$src))), (v8i16 QPR:$src)>;
def : Pat<(v8i16 (bitconvert (v4f32 QPR:$src))), (v8i16 QPR:$src)>;
+ def : Pat<(v8f16 (bitconvert (v2f64 QPR:$src))), (v8f16 QPR:$src)>;
def : Pat<(v16i8 (bitconvert (v2i64 QPR:$src))), (v16i8 QPR:$src)>;
def : Pat<(v16i8 (bitconvert (v4i32 QPR:$src))), (v16i8 QPR:$src)>;
def : Pat<(v16i8 (bitconvert (v8i16 QPR:$src))), (v16i8 QPR:$src)>;
@@ -7014,6 +7125,7 @@ def : Pat<(v2f64 (bitconvert (v2i64 QPR:$src))), (v2f64 QPR:$src)>;
let Predicates = [IsLE] in {
def : Pat<(v2f64 (bitconvert (v4i32 QPR:$src))), (v2f64 QPR:$src)>;
def : Pat<(v2f64 (bitconvert (v8i16 QPR:$src))), (v2f64 QPR:$src)>;
+ def : Pat<(v2f64 (bitconvert (v8f16 QPR:$src))), (v2f64 QPR:$src)>;
def : Pat<(v2f64 (bitconvert (v16i8 QPR:$src))), (v2f64 QPR:$src)>;
def : Pat<(v2f64 (bitconvert (v4f32 QPR:$src))), (v2f64 QPR:$src)>;
}
@@ -7039,6 +7151,7 @@ let Predicates = [IsBE] in {
def : Pat<(v8i8 (bitconvert (f64 DPR:$src))), (VREV64d8 DPR:$src)>;
def : Pat<(v8i8 (bitconvert (v2f32 DPR:$src))), (VREV32d8 DPR:$src)>;
def : Pat<(f64 (bitconvert (v2i32 DPR:$src))), (VREV64d32 DPR:$src)>;
+ def : Pat<(f64 (bitconvert (v4f16 DPR:$src))), (VREV64d16 DPR:$src)>;
def : Pat<(f64 (bitconvert (v4i16 DPR:$src))), (VREV64d16 DPR:$src)>;
def : Pat<(f64 (bitconvert (v8i8 DPR:$src))), (VREV64d8 DPR:$src)>;
def : Pat<(f64 (bitconvert (v2f32 DPR:$src))), (VREV64d32 DPR:$src)>;
@@ -7060,6 +7173,7 @@ let Predicates = [IsBE] in {
def : Pat<(v8i16 (bitconvert (v4i32 QPR:$src))), (VREV32q16 QPR:$src)>;
def : Pat<(v8i16 (bitconvert (v16i8 QPR:$src))), (VREV16q8 QPR:$src)>;
def : Pat<(v8i16 (bitconvert (v2f64 QPR:$src))), (VREV64q16 QPR:$src)>;
+ def : Pat<(v8f16 (bitconvert (v2f64 QPR:$src))), (VREV64q16 QPR:$src)>;
def : Pat<(v8i16 (bitconvert (v4f32 QPR:$src))), (VREV32q16 QPR:$src)>;
def : Pat<(v16i8 (bitconvert (v2i64 QPR:$src))), (VREV64q8 QPR:$src)>;
def : Pat<(v16i8 (bitconvert (v4i32 QPR:$src))), (VREV32q8 QPR:$src)>;
@@ -7068,10 +7182,12 @@ let Predicates = [IsBE] in {
def : Pat<(v16i8 (bitconvert (v4f32 QPR:$src))), (VREV32q8 QPR:$src)>;
def : Pat<(v4f32 (bitconvert (v2i64 QPR:$src))), (VREV64q32 QPR:$src)>;
def : Pat<(v4f32 (bitconvert (v8i16 QPR:$src))), (VREV32q16 QPR:$src)>;
+ def : Pat<(v4f32 (bitconvert (v8f16 QPR:$src))), (VREV32q16 QPR:$src)>;
def : Pat<(v4f32 (bitconvert (v16i8 QPR:$src))), (VREV32q8 QPR:$src)>;
def : Pat<(v4f32 (bitconvert (v2f64 QPR:$src))), (VREV64q32 QPR:$src)>;
def : Pat<(v2f64 (bitconvert (v4i32 QPR:$src))), (VREV64q32 QPR:$src)>;
def : Pat<(v2f64 (bitconvert (v8i16 QPR:$src))), (VREV64q16 QPR:$src)>;
+ def : Pat<(v2f64 (bitconvert (v8f16 QPR:$src))), (VREV64q16 QPR:$src)>;
def : Pat<(v2f64 (bitconvert (v16i8 QPR:$src))), (VREV64q8 QPR:$src)>;
def : Pat<(v2f64 (bitconvert (v4f32 QPR:$src))), (VREV64q32 QPR:$src)>;
}
diff --git a/lib/Target/ARM/ARMInstrThumb.td b/lib/Target/ARM/ARMInstrThumb.td
index c2bcc087e077..88aab47a79bf 100644
--- a/lib/Target/ARM/ARMInstrThumb.td
+++ b/lib/Target/ARM/ARMInstrThumb.td
@@ -270,6 +270,14 @@ def t_addrmode_sp : MemOperand,
let MIOperandInfo = (ops GPR:$base, i32imm:$offsimm);
}
+// Inspects parent to determine whether an or instruction can be implemented as
+// an add (i.e. whether we know overflow won't occur in the add).
+def AddLikeOrOp : ComplexPattern<i32, 1, "SelectAddLikeOr", [],
+ [SDNPWantParent]>;
+
+// Pattern to exclude immediates from matching
+def non_imm32 : PatLeaf<(i32 GPR), [{ return !isa<ConstantSDNode>(N); }]>;
+
//===----------------------------------------------------------------------===//
// Miscellaneous Instructions.
//
@@ -997,6 +1005,15 @@ let isAdd = 1 in {
}
}
+// Thumb has more flexible short encodings for ADD than ORR, so use those where
+// possible.
+def : T1Pat<(or AddLikeOrOp:$Rn, imm0_7:$imm), (tADDi3 $Rn, imm0_7:$imm)>;
+
+def : T1Pat<(or AddLikeOrOp:$Rn, imm8_255:$imm), (tADDi8 $Rn, imm8_255:$imm)>;
+
+def : T1Pat<(or AddLikeOrOp:$Rn, tGPR:$Rm), (tADDrr $Rn, $Rm)>;
+
+
def : tInstAlias <"add${s}${p} $Rdn, $Rm",
(tADDrr tGPR:$Rdn,s_cc_out:$s, tGPR:$Rdn, tGPR:$Rm, pred:$p)>;
@@ -1154,7 +1171,7 @@ def : tInstAlias <"movs $Rdn, $imm",
// A7-73: MOV(2) - mov setting flag.
-let hasSideEffects = 0 in {
+let hasSideEffects = 0, isMoveReg = 1 in {
def tMOVr : Thumb1pI<(outs GPR:$Rd), (ins GPR:$Rm), AddrModeNone,
2, IIC_iMOVr,
"mov", "\t$Rd, $Rm", "", []>,
diff --git a/lib/Target/ARM/ARMInstrThumb2.td b/lib/Target/ARM/ARMInstrThumb2.td
index 4592249f5795..c7133b6483ef 100644
--- a/lib/Target/ARM/ARMInstrThumb2.td
+++ b/lib/Target/ARM/ARMInstrThumb2.td
@@ -2104,6 +2104,12 @@ def : t2InstSubst<"sub${s}${p}.w $rd, $rn, $imm",
(t2ADDri GPRnopc:$rd, GPRnopc:$rn, t2_so_imm_neg:$imm, pred:$p, s_cc_out:$s)>;
def : t2InstSubst<"subw${p} $rd, $rn, $imm",
(t2ADDri12 GPRnopc:$rd, GPR:$rn, t2_so_imm_neg:$imm, pred:$p)>;
+def : t2InstSubst<"subw${p} $Rd, $Rn, $imm",
+ (t2ADDri12 GPRnopc:$Rd, GPR:$Rn, imm0_4095_neg:$imm, pred:$p)>;
+def : t2InstSubst<"sub${s}${p} $rd, $rn, $imm",
+ (t2ADDri GPRnopc:$rd, GPRnopc:$rn, t2_so_imm_neg:$imm, pred:$p, s_cc_out:$s)>;
+def : t2InstSubst<"sub${p} $rd, $rn, $imm",
+ (t2ADDri12 GPRnopc:$rd, GPR:$rn, t2_so_imm_neg:$imm, pred:$p)>;
// RSB
defm t2RSB : T2I_rbin_irs <0b1110, "rsb", sub>;
@@ -2594,6 +2600,18 @@ def : T2Pat<(or rGPR:$src, t2_so_imm_not:$imm),
def : T2Pat<(t2_so_imm_not:$src),
(t2MVNi t2_so_imm_not:$src)>;
+// There are shorter Thumb encodings for ADD than ORR, so to increase
+// Thumb2SizeReduction's chances later on we select a t2ADD for an or where
+// possible.
+def : T2Pat<(or AddLikeOrOp:$Rn, t2_so_imm:$imm),
+ (t2ADDri $Rn, t2_so_imm:$imm)>;
+
+def : T2Pat<(or AddLikeOrOp:$Rn, imm0_4095:$Rm),
+ (t2ADDri12 $Rn, imm0_4095:$Rm)>;
+
+def : T2Pat<(or AddLikeOrOp:$Rn, non_imm32:$Rm),
+ (t2ADDrr $Rn, $Rm)>;
+
//===----------------------------------------------------------------------===//
// Multiply Instructions.
//
@@ -2661,7 +2679,9 @@ class T2SMMUL<bits<4> op7_4, string opc, list<dag> pattern>
}
def t2SMMUL : T2SMMUL<0b0000, "smmul", [(set rGPR:$Rd, (mulhs rGPR:$Rn,
rGPR:$Rm))]>;
-def t2SMMULR : T2SMMUL<0b0001, "smmulr", []>;
+def t2SMMULR :
+ T2SMMUL<0b0001, "smmulr",
+ [(set rGPR:$Rd, (ARMsmmlar rGPR:$Rn, rGPR:$Rm, (i32 0)))]>;
class T2FourRegSMMLA<bits<3> op22_20, bits<4> op7_4, string opc,
list<dag> pattern>
@@ -2677,9 +2697,11 @@ class T2FourRegSMMLA<bits<3> op22_20, bits<4> op7_4, string opc,
def t2SMMLA : T2FourRegSMMLA<0b101, 0b0000, "smmla",
[(set rGPR:$Rd, (add (mulhs rGPR:$Rm, rGPR:$Rn), rGPR:$Ra))]>;
-def t2SMMLAR: T2FourRegSMMLA<0b101, 0b0001, "smmlar", []>;
+def t2SMMLAR: T2FourRegSMMLA<0b101, 0b0001, "smmlar",
+ [(set rGPR:$Rd, (ARMsmmlar rGPR:$Rn, rGPR:$Rm, rGPR:$Ra))]>;
def t2SMMLS: T2FourRegSMMLA<0b110, 0b0000, "smmls", []>;
-def t2SMMLSR: T2FourRegSMMLA<0b110, 0b0001, "smmlsr", []>;
+def t2SMMLSR: T2FourRegSMMLA<0b110, 0b0001, "smmlsr",
+ [(set rGPR:$Rd, (ARMsmmlsr rGPR:$Rn, rGPR:$Rm, rGPR:$Ra))]>;
class T2ThreeRegSMUL<bits<3> op22_20, bits<2> op5_4, string opc,
list<dag> pattern>
@@ -3193,6 +3215,12 @@ def t2ISB : T2I<(outs), (ins instsyncb_opt:$opt), NoItinerary,
let Inst{31-4} = 0xf3bf8f6;
let Inst{3-0} = opt;
}
+
+let hasNoSchedulingInfo = 1 in
+def t2TSB : T2I<(outs), (ins tsb_opt:$opt), NoItinerary,
+ "tsb", "\t$opt", []>, Requires<[IsThumb, HasV8_4a]> {
+ let Inst{31-0} = 0xf3af8012;
+}
}
class T2I_ldrex<bits<4> opcod, dag oops, dag iops, AddrMode am, int sz,
@@ -3696,6 +3724,8 @@ def : t2InstAlias<"esb$p.w", (t2HINT 16, pred:$p), 1> {
def : t2InstAlias<"esb$p", (t2HINT 16, pred:$p), 0> {
let Predicates = [IsThumb2, HasRAS];
}
+def : t2InstAlias<"csdb$p.w", (t2HINT 20, pred:$p), 0>;
+def : t2InstAlias<"csdb$p", (t2HINT 20, pred:$p), 1>;
def t2DBG : T2I<(outs), (ins imm0_15:$opt), NoItinerary, "dbg", "\t$opt",
[(int_arm_dbg imm0_15:$opt)]> {
@@ -4713,12 +4743,24 @@ def : t2InstSubst<"bic${s}${p} $Rd, $Rn, $imm",
def : t2InstSubst<"bic${s}${p} $Rdn, $imm",
(t2ANDri rGPR:$Rdn, rGPR:$Rdn, t2_so_imm_not:$imm,
pred:$p, cc_out:$s)>;
+def : t2InstSubst<"bic${s}${p}.w $Rd, $Rn, $imm",
+ (t2ANDri rGPR:$Rd, rGPR:$Rn, t2_so_imm_not:$imm,
+ pred:$p, cc_out:$s)>;
+def : t2InstSubst<"bic${s}${p}.w $Rdn, $imm",
+ (t2ANDri rGPR:$Rdn, rGPR:$Rdn, t2_so_imm_not:$imm,
+ pred:$p, cc_out:$s)>;
def : t2InstSubst<"and${s}${p} $Rd, $Rn, $imm",
(t2BICri rGPR:$Rd, rGPR:$Rn, t2_so_imm_not:$imm,
pred:$p, cc_out:$s)>;
def : t2InstSubst<"and${s}${p} $Rdn, $imm",
(t2BICri rGPR:$Rdn, rGPR:$Rdn, t2_so_imm_not:$imm,
pred:$p, cc_out:$s)>;
+def : t2InstSubst<"and${s}${p}.w $Rd, $Rn, $imm",
+ (t2BICri rGPR:$Rd, rGPR:$Rn, t2_so_imm_not:$imm,
+ pred:$p, cc_out:$s)>;
+def : t2InstSubst<"and${s}${p}.w $Rdn, $imm",
+ (t2BICri rGPR:$Rdn, rGPR:$Rdn, t2_so_imm_not:$imm,
+ pred:$p, cc_out:$s)>;
// And ORR <--> ORN
def : t2InstSubst<"orn${s}${p} $Rd, $Rn, $imm",
(t2ORRri rGPR:$Rd, rGPR:$Rn, t2_so_imm_not:$imm,
diff --git a/lib/Target/ARM/ARMInstrVFP.td b/lib/Target/ARM/ARMInstrVFP.td
index 22e157a7480b..2f14b78c91fd 100644
--- a/lib/Target/ARM/ARMInstrVFP.td
+++ b/lib/Target/ARM/ARMInstrVFP.td
@@ -17,11 +17,19 @@ def SDT_VMOVDRR : SDTypeProfile<1, 2, [SDTCisVT<0, f64>, SDTCisVT<1, i32>,
def SDT_VMOVRRD : SDTypeProfile<2, 1, [SDTCisVT<0, i32>, SDTCisSameAs<0, 1>,
SDTCisVT<2, f64>]>;
+def SDT_VMOVSR : SDTypeProfile<1, 1, [SDTCisVT<0, f32>, SDTCisVT<1, i32>]>;
+
def arm_fmstat : SDNode<"ARMISD::FMSTAT", SDTNone, [SDNPInGlue, SDNPOutGlue]>;
def arm_cmpfp : SDNode<"ARMISD::CMPFP", SDT_ARMFCmp, [SDNPOutGlue]>;
def arm_cmpfp0 : SDNode<"ARMISD::CMPFPw0", SDT_CMPFP0, [SDNPOutGlue]>;
def arm_fmdrr : SDNode<"ARMISD::VMOVDRR", SDT_VMOVDRR>;
def arm_fmrrd : SDNode<"ARMISD::VMOVRRD", SDT_VMOVRRD>;
+def arm_vmovsr : SDNode<"ARMISD::VMOVSR", SDT_VMOVSR>;
+
+def SDT_VMOVhr : SDTypeProfile<1, 1, [SDTCisFP<0>, SDTCisVT<1, i32>] >;
+def SDT_VMOVrh : SDTypeProfile<1, 1, [SDTCisVT<0, i32>, SDTCisFP<1>] >;
+def arm_vmovhr : SDNode<"ARMISD::VMOVhr", SDT_VMOVhr>;
+def arm_vmovrh : SDNode<"ARMISD::VMOVrh", SDT_VMOVrh>;
//===----------------------------------------------------------------------===//
// Operand Definitions.
@@ -39,7 +47,7 @@ def vfp_f16imm : Operand<f16>,
}], SDNodeXForm<fpimm, [{
APFloat InVal = N->getValueAPF();
uint32_t enc = ARM_AM::getFP16Imm(InVal);
- return CurDAG->getTargetConstant(enc, MVT::i32);
+ return CurDAG->getTargetConstant(enc, SDLoc(N), MVT::i32);
}]>> {
let PrintMethod = "printFPImmOperand";
let ParserMatchClass = FPImmOperand;
@@ -69,10 +77,19 @@ def vfp_f64imm : Operand<f64>,
let ParserMatchClass = FPImmOperand;
}
+def alignedload16 : PatFrag<(ops node:$ptr), (load node:$ptr), [{
+ return cast<LoadSDNode>(N)->getAlignment() >= 2;
+}]>;
+
def alignedload32 : PatFrag<(ops node:$ptr), (load node:$ptr), [{
return cast<LoadSDNode>(N)->getAlignment() >= 4;
}]>;
+def alignedstore16 : PatFrag<(ops node:$val, node:$ptr),
+ (store node:$val, node:$ptr), [{
+ return cast<StoreSDNode>(N)->getAlignment() >= 2;
+}]>;
+
def alignedstore32 : PatFrag<(ops node:$val, node:$ptr),
(store node:$val, node:$ptr), [{
return cast<StoreSDNode>(N)->getAlignment() >= 4;
@@ -113,9 +130,9 @@ def VLDRS : ASI5<0b1101, 0b01, (outs SPR:$Sd), (ins addrmode5:$addr),
let D = VFPNeonDomain;
}
-def VLDRH : AHI5<0b1101, 0b01, (outs SPR:$Sd), (ins addrmode5fp16:$addr),
+def VLDRH : AHI5<0b1101, 0b01, (outs HPR:$Sd), (ins addrmode5fp16:$addr),
IIC_fpLoad16, "vldr", ".16\t$Sd, $addr",
- []>,
+ [(set HPR:$Sd, (alignedload16 addrmode5fp16:$addr))]>,
Requires<[HasFullFP16]>;
} // End of 'let canFoldAsLoad = 1, isReMaterializable = 1 in'
@@ -132,9 +149,9 @@ def VSTRS : ASI5<0b1101, 0b00, (outs), (ins SPR:$Sd, addrmode5:$addr),
let D = VFPNeonDomain;
}
-def VSTRH : AHI5<0b1101, 0b00, (outs), (ins SPR:$Sd, addrmode5fp16:$addr),
+def VSTRH : AHI5<0b1101, 0b00, (outs), (ins HPR:$Sd, addrmode5fp16:$addr),
IIC_fpStore16, "vstr", ".16\t$Sd, $addr",
- []>,
+ [(alignedstore16 HPR:$Sd, addrmode5fp16:$addr)]>,
Requires<[HasFullFP16]>;
//===----------------------------------------------------------------------===//
@@ -335,9 +352,9 @@ def VADDS : ASbIn<0b11100, 0b11, 0, 0,
let TwoOperandAliasConstraint = "$Sn = $Sd" in
def VADDH : AHbI<0b11100, 0b11, 0, 0,
- (outs SPR:$Sd), (ins SPR:$Sn, SPR:$Sm),
+ (outs HPR:$Sd), (ins HPR:$Sn, HPR:$Sm),
IIC_fpALU16, "vadd", ".f16\t$Sd, $Sn, $Sm",
- []>,
+ [(set HPR:$Sd, (fadd HPR:$Sn, HPR:$Sm))]>,
Sched<[WriteFPALU32]>;
let TwoOperandAliasConstraint = "$Dn = $Dd" in
@@ -360,9 +377,9 @@ def VSUBS : ASbIn<0b11100, 0b11, 1, 0,
let TwoOperandAliasConstraint = "$Sn = $Sd" in
def VSUBH : AHbI<0b11100, 0b11, 1, 0,
- (outs SPR:$Sd), (ins SPR:$Sn, SPR:$Sm),
+ (outs HPR:$Sd), (ins HPR:$Sn, HPR:$Sm),
IIC_fpALU16, "vsub", ".f16\t$Sd, $Sn, $Sm",
- []>,
+ [(set HPR:$Sd, (fsub HPR:$Sn, HPR:$Sm))]>,
Sched<[WriteFPALU32]>;
let TwoOperandAliasConstraint = "$Dn = $Dd" in
@@ -381,9 +398,9 @@ def VDIVS : ASbI<0b11101, 0b00, 0, 0,
let TwoOperandAliasConstraint = "$Sn = $Sd" in
def VDIVH : AHbI<0b11101, 0b00, 0, 0,
- (outs SPR:$Sd), (ins SPR:$Sn, SPR:$Sm),
+ (outs HPR:$Sd), (ins HPR:$Sn, HPR:$Sm),
IIC_fpDIV16, "vdiv", ".f16\t$Sd, $Sn, $Sm",
- []>,
+ [(set HPR:$Sd, (fdiv HPR:$Sn, HPR:$Sm))]>,
Sched<[WriteFPDIV32]>;
let TwoOperandAliasConstraint = "$Dn = $Dd" in
@@ -406,9 +423,9 @@ def VMULS : ASbIn<0b11100, 0b10, 0, 0,
let TwoOperandAliasConstraint = "$Sn = $Sd" in
def VMULH : AHbI<0b11100, 0b10, 0, 0,
- (outs SPR:$Sd), (ins SPR:$Sn, SPR:$Sm),
+ (outs HPR:$Sd), (ins HPR:$Sn, HPR:$Sm),
IIC_fpMUL16, "vmul", ".f16\t$Sd, $Sn, $Sm",
- []>,
+ [(set HPR:$Sd, (fmul HPR:$Sn, HPR:$Sm))]>,
Sched<[WriteFPMUL32, ReadFPMUL, ReadFPMUL]>;
def VNMULD : ADbI<0b11100, 0b10, 1, 0,
@@ -428,18 +445,18 @@ def VNMULS : ASbI<0b11100, 0b10, 1, 0,
}
def VNMULH : AHbI<0b11100, 0b10, 1, 0,
- (outs SPR:$Sd), (ins SPR:$Sn, SPR:$Sm),
+ (outs HPR:$Sd), (ins HPR:$Sn, HPR:$Sm),
IIC_fpMUL16, "vnmul", ".f16\t$Sd, $Sn, $Sm",
- []>,
+ [(set HPR:$Sd, (fneg (fmul HPR:$Sn, HPR:$Sm)))]>,
Sched<[WriteFPMUL32, ReadFPMUL, ReadFPMUL]>;
multiclass vsel_inst<string op, bits<2> opc, int CC> {
let DecoderNamespace = "VFPV8", PostEncoderMethod = "",
Uses = [CPSR], AddedComplexity = 4 in {
def H : AHbInp<0b11100, opc, 0,
- (outs SPR:$Sd), (ins SPR:$Sn, SPR:$Sm),
+ (outs HPR:$Sd), (ins HPR:$Sn, HPR:$Sm),
NoItinerary, !strconcat("vsel", op, ".f16\t$Sd, $Sn, $Sm"),
- []>,
+ [(set HPR:$Sd, (ARMcmov HPR:$Sm, HPR:$Sn, CC))]>,
Requires<[HasFullFP16]>;
def S : ASbInp<0b11100, opc, 0,
@@ -465,9 +482,9 @@ defm VSELVS : vsel_inst<"vs", 0b01, 6>;
multiclass vmaxmin_inst<string op, bit opc, SDNode SD> {
let DecoderNamespace = "VFPV8", PostEncoderMethod = "" in {
def H : AHbInp<0b11101, 0b00, opc,
- (outs SPR:$Sd), (ins SPR:$Sn, SPR:$Sm),
+ (outs HPR:$Sd), (ins HPR:$Sn, HPR:$Sm),
NoItinerary, !strconcat(op, ".f16\t$Sd, $Sn, $Sm"),
- []>,
+ [(set HPR:$Sd, (SD HPR:$Sn, HPR:$Sm))]>,
Requires<[HasFullFP16]>;
def S : ASbInp<0b11101, 0b00, opc,
@@ -511,9 +528,9 @@ def VCMPES : ASuI<0b11101, 0b11, 0b0100, 0b11, 0,
}
def VCMPEH : AHuI<0b11101, 0b11, 0b0100, 0b11, 0,
- (outs), (ins SPR:$Sd, SPR:$Sm),
+ (outs), (ins HPR:$Sd, HPR:$Sm),
IIC_fpCMP16, "vcmpe", ".f16\t$Sd, $Sm",
- []>;
+ [(arm_cmpfp HPR:$Sd, HPR:$Sm, (i32 1))]>;
def VCMPD : ADuI<0b11101, 0b11, 0b0100, 0b01, 0,
(outs), (ins DPR:$Dd, DPR:$Dm),
@@ -530,9 +547,9 @@ def VCMPS : ASuI<0b11101, 0b11, 0b0100, 0b01, 0,
}
def VCMPH : AHuI<0b11101, 0b11, 0b0100, 0b01, 0,
- (outs), (ins SPR:$Sd, SPR:$Sm),
+ (outs), (ins HPR:$Sd, HPR:$Sm),
IIC_fpCMP16, "vcmp", ".f16\t$Sd, $Sm",
- []>;
+ [(arm_cmpfp HPR:$Sd, HPR:$Sm, (i32 0))]>;
} // Defs = [FPSCR_NZCV]
//===----------------------------------------------------------------------===//
@@ -580,9 +597,9 @@ def VCMPEZS : ASuI<0b11101, 0b11, 0b0101, 0b11, 0,
}
def VCMPEZH : AHuI<0b11101, 0b11, 0b0101, 0b11, 0,
- (outs), (ins SPR:$Sd),
+ (outs), (ins HPR:$Sd),
IIC_fpCMP16, "vcmpe", ".f16\t$Sd, #0",
- []> {
+ [(arm_cmpfp0 HPR:$Sd, (i32 1))]> {
let Inst{3-0} = 0b0000;
let Inst{5} = 0;
}
@@ -608,9 +625,9 @@ def VCMPZS : ASuI<0b11101, 0b11, 0b0101, 0b01, 0,
}
def VCMPZH : AHuI<0b11101, 0b11, 0b0101, 0b01, 0,
- (outs), (ins SPR:$Sd),
+ (outs), (ins HPR:$Sd),
IIC_fpCMP16, "vcmp", ".f16\t$Sd, #0",
- []> {
+ [(arm_cmpfp0 HPR:$Sd, (i32 0))]> {
let Inst{3-0} = 0b0000;
let Inst{5} = 0;
}
@@ -658,20 +675,29 @@ def VCVTSD : VFPAI<(outs SPR:$Sd), (ins DPR:$Dm), VFPUnaryFrm,
let Predicates = [HasVFP2, HasDPVFP];
}
-// Between half, single and double-precision. For disassembly only.
-
+// Between half, single and double-precision.
def VCVTBHS: ASuI<0b11101, 0b11, 0b0010, 0b01, 0, (outs SPR:$Sd), (ins SPR:$Sm),
/* FIXME */ IIC_fpCVTSH, "vcvtb", ".f32.f16\t$Sd, $Sm",
- [/* For disassembly only; pattern left blank */]>,
+ [/* Intentionally left blank, see patterns below */]>,
Requires<[HasFP16]>,
Sched<[WriteFPCVT]>;
+def : FullFP16Pat<(f32 (fpextend HPR:$Sm)),
+ (VCVTBHS (COPY_TO_REGCLASS HPR:$Sm, SPR))>;
+def : FP16Pat<(f16_to_fp GPR:$a),
+ (VCVTBHS (COPY_TO_REGCLASS GPR:$a, SPR))>;
+
def VCVTBSH: ASuI<0b11101, 0b11, 0b0011, 0b01, 0, (outs SPR:$Sd), (ins SPR:$Sm),
/* FIXME */ IIC_fpCVTHS, "vcvtb", ".f16.f32\t$Sd, $Sm",
- [/* For disassembly only; pattern left blank */]>,
+ [/* Intentionally left blank, see patterns below */]>,
Requires<[HasFP16]>,
Sched<[WriteFPCVT]>;
+def : FullFP16Pat<(f16 (fpround SPR:$Sm)),
+ (COPY_TO_REGCLASS (VCVTBSH SPR:$Sm), HPR)>;
+def : FP16Pat<(fp_to_f16 SPR:$a),
+ (i32 (COPY_TO_REGCLASS (VCVTBSH SPR:$a), GPR))>;
+
def VCVTTHS: ASuI<0b11101, 0b11, 0b0010, 0b11, 0, (outs SPR:$Sd), (ins SPR:$Sm),
/* FIXME */ IIC_fpCVTSH, "vcvtt", ".f32.f16\t$Sd, $Sm",
[/* For disassembly only; pattern left blank */]>,
@@ -687,7 +713,8 @@ def VCVTTSH: ASuI<0b11101, 0b11, 0b0011, 0b11, 0, (outs SPR:$Sd), (ins SPR:$Sm),
def VCVTBHD : ADuI<0b11101, 0b11, 0b0010, 0b01, 0,
(outs DPR:$Dd), (ins SPR:$Sm),
NoItinerary, "vcvtb", ".f64.f16\t$Dd, $Sm",
- []>, Requires<[HasFPARMv8, HasDPVFP]>,
+ [/* Intentionally left blank, see patterns below */]>,
+ Requires<[HasFPARMv8, HasDPVFP]>,
Sched<[WriteFPCVT]> {
// Instruction operands.
bits<5> Sm;
@@ -697,10 +724,16 @@ def VCVTBHD : ADuI<0b11101, 0b11, 0b0010, 0b01, 0,
let Inst{5} = Sm{0};
}
+def : FullFP16Pat<(f64 (fpextend HPR:$Sm)),
+ (VCVTBHD (COPY_TO_REGCLASS HPR:$Sm, SPR))>;
+def : FP16Pat<(f64 (f16_to_fp GPR:$a)),
+ (VCVTBHD (COPY_TO_REGCLASS GPR:$a, SPR))>;
+
def VCVTBDH : ADuI<0b11101, 0b11, 0b0011, 0b01, 0,
(outs SPR:$Sd), (ins DPR:$Dm),
NoItinerary, "vcvtb", ".f16.f64\t$Sd, $Dm",
- []>, Requires<[HasFPARMv8, HasDPVFP]> {
+ [/* Intentionally left blank, see patterns below */]>,
+ Requires<[HasFPARMv8, HasDPVFP]> {
// Instruction operands.
bits<5> Sd;
bits<5> Dm;
@@ -712,6 +745,11 @@ def VCVTBDH : ADuI<0b11101, 0b11, 0b0011, 0b01, 0,
let Inst{22} = Sd{0};
}
+def : FullFP16Pat<(f16 (fpround DPR:$Dm)),
+ (COPY_TO_REGCLASS (VCVTBDH DPR:$Dm), HPR)>;
+def : FP16Pat<(fp_to_f16 (f64 DPR:$a)),
+ (i32 (COPY_TO_REGCLASS (VCVTBDH DPR:$a), GPR))>;
+
def VCVTTHD : ADuI<0b11101, 0b11, 0b0010, 0b11, 0,
(outs DPR:$Dd), (ins SPR:$Sm),
NoItinerary, "vcvtt", ".f64.f16\t$Dd, $Sm",
@@ -739,23 +777,11 @@ def VCVTTDH : ADuI<0b11101, 0b11, 0b0011, 0b11, 0,
let Inst{5} = Dm{4};
}
-def : Pat<(fp_to_f16 SPR:$a),
- (i32 (COPY_TO_REGCLASS (VCVTBSH SPR:$a), GPR))>;
-
-def : Pat<(fp_to_f16 (f64 DPR:$a)),
- (i32 (COPY_TO_REGCLASS (VCVTBDH DPR:$a), GPR))>;
-
-def : Pat<(f16_to_fp GPR:$a),
- (VCVTBHS (COPY_TO_REGCLASS GPR:$a, SPR))>;
-
-def : Pat<(f64 (f16_to_fp GPR:$a)),
- (VCVTBHD (COPY_TO_REGCLASS GPR:$a, SPR))>;
-
multiclass vcvt_inst<string opc, bits<2> rm,
SDPatternOperator node = null_frag> {
let PostEncoderMethod = "", DecoderNamespace = "VFPV8" in {
def SH : AHuInp<0b11101, 0b11, 0b1100, 0b11, 0,
- (outs SPR:$Sd), (ins SPR:$Sm),
+ (outs SPR:$Sd), (ins HPR:$Sm),
NoItinerary, !strconcat("vcvt", opc, ".s32.f16\t$Sd, $Sm"),
[]>,
Requires<[HasFullFP16]> {
@@ -763,7 +789,7 @@ multiclass vcvt_inst<string opc, bits<2> rm,
}
def UH : AHuInp<0b11101, 0b11, 0b1100, 0b01, 0,
- (outs SPR:$Sd), (ins SPR:$Sm),
+ (outs SPR:$Sd), (ins HPR:$Sm),
NoItinerary, !strconcat("vcvt", opc, ".u32.f16\t$Sd, $Sm"),
[]>,
Requires<[HasFullFP16]> {
@@ -818,6 +844,17 @@ multiclass vcvt_inst<string opc, bits<2> rm,
}
let Predicates = [HasFPARMv8] in {
+ let Predicates = [HasFullFP16] in {
+ def : Pat<(i32 (fp_to_sint (node HPR:$a))),
+ (COPY_TO_REGCLASS
+ (!cast<Instruction>(NAME#"SH") HPR:$a),
+ GPR)>;
+
+ def : Pat<(i32 (fp_to_uint (node HPR:$a))),
+ (COPY_TO_REGCLASS
+ (!cast<Instruction>(NAME#"UH") HPR:$a),
+ GPR)>;
+ }
def : Pat<(i32 (fp_to_sint (node SPR:$a))),
(COPY_TO_REGCLASS
(!cast<Instruction>(NAME#"SS") SPR:$a),
@@ -859,9 +896,9 @@ def VNEGS : ASuIn<0b11101, 0b11, 0b0001, 0b01, 0,
}
def VNEGH : AHuI<0b11101, 0b11, 0b0001, 0b01, 0,
- (outs SPR:$Sd), (ins SPR:$Sm),
+ (outs HPR:$Sd), (ins HPR:$Sm),
IIC_fpUNA16, "vneg", ".f16\t$Sd, $Sm",
- []>;
+ [(set HPR:$Sd, (fneg HPR:$Sm))]>;
multiclass vrint_inst_zrx<string opc, bit op, bit op2, SDPatternOperator node> {
def H : AHuI<0b11101, 0b11, 0b0110, 0b11, 0,
@@ -940,7 +977,7 @@ multiclass vrint_inst_anpm<string opc, bits<2> rm,
}
defm VRINTA : vrint_inst_anpm<"a", 0b00, fround>;
-defm VRINTN : vrint_inst_anpm<"n", 0b01>;
+defm VRINTN : vrint_inst_anpm<"n", 0b01, int_arm_neon_vrintn>;
defm VRINTP : vrint_inst_anpm<"p", 0b10, fceil>;
defm VRINTM : vrint_inst_anpm<"m", 0b11, ffloor>;
@@ -962,6 +999,7 @@ def VSQRTH : AHuI<0b11101, 0b11, 0b0001, 0b11, 0,
[]>;
let hasSideEffects = 0 in {
+let isMoveReg = 1 in {
def VMOVD : ADuI<0b11101, 0b11, 0b0000, 0b01, 0,
(outs DPR:$Dd), (ins DPR:$Dm),
IIC_fpUNA64, "vmov", ".f64\t$Dd, $Dm", []>;
@@ -969,6 +1007,7 @@ def VMOVD : ADuI<0b11101, 0b11, 0b0000, 0b01, 0,
def VMOVS : ASuI<0b11101, 0b11, 0b0000, 0b01, 0,
(outs SPR:$Sd), (ins SPR:$Sm),
IIC_fpUNA32, "vmov", ".f32\t$Sd, $Sm", []>;
+} // isMoveReg
let PostEncoderMethod = "", DecoderNamespace = "VFPV8" in {
def VMOVH : ASuInp<0b11101, 0b11, 0b0000, 0b01, 0,
@@ -987,6 +1026,7 @@ def VINSH : ASuInp<0b11101, 0b11, 0b0000, 0b11, 0,
// FP <-> GPR Copies. Int <-> FP Conversions.
//
+let isMoveReg = 1 in {
def VMOVRS : AVConv2I<0b11100001, 0b1010,
(outs GPR:$Rt), (ins SPR:$Sn),
IIC_fpMOVSI, "vmov", "\t$Rt, $Sn",
@@ -1032,6 +1072,8 @@ def VMOVSR : AVConv4I<0b11100000, 0b1010,
// pipelines.
let D = VFPNeonDomain;
}
+} // isMoveReg
+def : Pat<(arm_vmovsr GPR:$Rt), (VMOVSR GPR:$Rt)>, Requires<[HasVFP2, UseVMOVSR]>;
let hasSideEffects = 0 in {
def VMOVRRD : AVConv3I<0b11000101, 0b1011,
@@ -1160,9 +1202,9 @@ def VMOVSRR : AVConv5I<0b11000100, 0b1010,
// Move H->R, clearing top 16 bits
def VMOVRH : AVConv2I<0b11100001, 0b1001,
- (outs GPR:$Rt), (ins SPR:$Sn),
+ (outs GPR:$Rt), (ins HPR:$Sn),
IIC_fpMOVSI, "vmov", ".f16\t$Rt, $Sn",
- []>,
+ [(set GPR:$Rt, (arm_vmovrh HPR:$Sn))]>,
Requires<[HasFullFP16]>,
Sched<[WriteFPMOV]> {
// Instruction operands.
@@ -1180,9 +1222,9 @@ def VMOVRH : AVConv2I<0b11100001, 0b1001,
// Move R->H, clearing top 16 bits
def VMOVHR : AVConv4I<0b11100000, 0b1001,
- (outs SPR:$Sn), (ins GPR:$Rt),
+ (outs HPR:$Sn), (ins GPR:$Rt),
IIC_fpMOVIS, "vmov", ".f16\t$Sn, $Rt",
- []>,
+ [(set HPR:$Sn, (arm_vmovhr GPR:$Rt))]>,
Requires<[HasFullFP16]>,
Sched<[WriteFPMOV]> {
// Instruction operands.
@@ -1297,13 +1339,16 @@ def : VFPNoNEONPat<(f32 (sint_to_fp (i32 (alignedload32 addrmode5:$a)))),
(VSITOS (VLDRS addrmode5:$a))>;
def VSITOH : AVConv1IHs_Encode<0b11101, 0b11, 0b1000, 0b1001,
- (outs SPR:$Sd), (ins SPR:$Sm),
+ (outs HPR:$Sd), (ins SPR:$Sm),
IIC_fpCVTIH, "vcvt", ".f16.s32\t$Sd, $Sm",
[]>,
Sched<[WriteFPCVT]> {
let Inst{7} = 1; // s32
}
+def : VFPNoNEONPat<(f16 (sint_to_fp GPR:$a)),
+ (VSITOH (COPY_TO_REGCLASS GPR:$a, SPR))>;
+
def VUITOD : AVConv1IDs_Encode<0b11101, 0b11, 0b1000, 0b1011,
(outs DPR:$Dd), (ins SPR:$Sm),
IIC_fpCVTID, "vcvt", ".f64.u32\t$Dd, $Sm",
@@ -1339,13 +1384,16 @@ def : VFPNoNEONPat<(f32 (uint_to_fp (i32 (alignedload32 addrmode5:$a)))),
(VUITOS (VLDRS addrmode5:$a))>;
def VUITOH : AVConv1IHs_Encode<0b11101, 0b11, 0b1000, 0b1001,
- (outs SPR:$Sd), (ins SPR:$Sm),
+ (outs HPR:$Sd), (ins SPR:$Sm),
IIC_fpCVTIH, "vcvt", ".f16.u32\t$Sd, $Sm",
[]>,
Sched<[WriteFPCVT]> {
let Inst{7} = 0; // u32
}
+def : VFPNoNEONPat<(f16 (uint_to_fp GPR:$a)),
+ (VUITOH (COPY_TO_REGCLASS GPR:$a, SPR))>;
+
// FP -> Int:
class AVConv1IsD_Encode<bits<5> opcod1, bits<2> opcod2, bits<4> opcod3,
@@ -1440,13 +1488,16 @@ def : VFPNoNEONPat<(alignedstore32 (i32 (fp_to_sint (f32 SPR:$a))),
(VSTRS (VTOSIZS SPR:$a), addrmode5:$ptr)>;
def VTOSIZH : AVConv1IsH_Encode<0b11101, 0b11, 0b1101, 0b1001,
- (outs SPR:$Sd), (ins SPR:$Sm),
+ (outs SPR:$Sd), (ins HPR:$Sm),
IIC_fpCVTHI, "vcvt", ".s32.f16\t$Sd, $Sm",
[]>,
Sched<[WriteFPCVT]> {
let Inst{7} = 1; // Z bit
}
+def : VFPNoNEONPat<(i32 (fp_to_sint HPR:$a)),
+ (COPY_TO_REGCLASS (VTOSIZH HPR:$a), GPR)>;
+
def VTOUIZD : AVConv1IsD_Encode<0b11101, 0b11, 0b1100, 0b1011,
(outs SPR:$Sd), (ins DPR:$Dm),
IIC_fpCVTDI, "vcvt", ".u32.f64\t$Sd, $Dm",
@@ -1483,13 +1534,16 @@ def : VFPNoNEONPat<(alignedstore32 (i32 (fp_to_uint (f32 SPR:$a))),
(VSTRS (VTOUIZS SPR:$a), addrmode5:$ptr)>;
def VTOUIZH : AVConv1IsH_Encode<0b11101, 0b11, 0b1100, 0b1001,
- (outs SPR:$Sd), (ins SPR:$Sm),
+ (outs SPR:$Sd), (ins HPR:$Sm),
IIC_fpCVTHI, "vcvt", ".u32.f16\t$Sd, $Sm",
[]>,
Sched<[WriteFPCVT]> {
let Inst{7} = 1; // Z bit
}
+def : VFPNoNEONPat<(i32 (fp_to_uint HPR:$a)),
+ (COPY_TO_REGCLASS (VTOUIZH HPR:$a), GPR)>;
+
// And the Z bit '0' variants, i.e. use the rounding mode specified by FPSCR.
let Uses = [FPSCR] in {
def VTOSIRD : AVConv1IsD_Encode<0b11101, 0b11, 0b1101, 0b1011,
@@ -1773,9 +1827,10 @@ def VMLAS : ASbIn<0b11100, 0b00, 0, 0,
}
def VMLAH : AHbI<0b11100, 0b00, 0, 0,
- (outs SPR:$Sd), (ins SPR:$Sdin, SPR:$Sn, SPR:$Sm),
+ (outs HPR:$Sd), (ins HPR:$Sdin, HPR:$Sn, HPR:$Sm),
IIC_fpMAC16, "vmla", ".f16\t$Sd, $Sn, $Sm",
- []>,
+ [(set HPR:$Sd, (fadd_mlx (fmul_su HPR:$Sn, HPR:$Sm),
+ HPR:$Sdin))]>,
RegConstraint<"$Sdin = $Sd">,
Requires<[HasFullFP16,UseFPVMLx,DontUseFusedMAC]>;
@@ -1785,6 +1840,10 @@ def : Pat<(fadd_mlx DPR:$dstin, (fmul_su DPR:$a, (f64 DPR:$b))),
def : Pat<(fadd_mlx SPR:$dstin, (fmul_su SPR:$a, SPR:$b)),
(VMLAS SPR:$dstin, SPR:$a, SPR:$b)>,
Requires<[HasVFP2,DontUseNEONForFP, UseFPVMLx,DontUseFusedMAC]>;
+def : Pat<(fadd_mlx HPR:$dstin, (fmul_su HPR:$a, HPR:$b)),
+ (VMLAH HPR:$dstin, HPR:$a, HPR:$b)>,
+ Requires<[HasFullFP16,DontUseNEONForFP, UseFPVMLx,DontUseFusedMAC]>;
+
def VMLSD : ADbI<0b11100, 0b00, 1, 0,
(outs DPR:$Dd), (ins DPR:$Ddin, DPR:$Dn, DPR:$Dm),
@@ -1809,9 +1868,10 @@ def VMLSS : ASbIn<0b11100, 0b00, 1, 0,
}
def VMLSH : AHbI<0b11100, 0b00, 1, 0,
- (outs SPR:$Sd), (ins SPR:$Sdin, SPR:$Sn, SPR:$Sm),
+ (outs HPR:$Sd), (ins HPR:$Sdin, HPR:$Sn, HPR:$Sm),
IIC_fpMAC16, "vmls", ".f16\t$Sd, $Sn, $Sm",
- []>,
+ [(set HPR:$Sd, (fadd_mlx (fneg (fmul_su HPR:$Sn, HPR:$Sm)),
+ HPR:$Sdin))]>,
RegConstraint<"$Sdin = $Sd">,
Requires<[HasFullFP16,UseFPVMLx,DontUseFusedMAC]>;
@@ -1821,6 +1881,9 @@ def : Pat<(fsub_mlx DPR:$dstin, (fmul_su DPR:$a, (f64 DPR:$b))),
def : Pat<(fsub_mlx SPR:$dstin, (fmul_su SPR:$a, SPR:$b)),
(VMLSS SPR:$dstin, SPR:$a, SPR:$b)>,
Requires<[HasVFP2,DontUseNEONForFP,UseFPVMLx,DontUseFusedMAC]>;
+def : Pat<(fsub_mlx HPR:$dstin, (fmul_su HPR:$a, HPR:$b)),
+ (VMLSH HPR:$dstin, HPR:$a, HPR:$b)>,
+ Requires<[HasFullFP16,DontUseNEONForFP,UseFPVMLx,DontUseFusedMAC]>;
def VNMLAD : ADbI<0b11100, 0b01, 1, 0,
(outs DPR:$Dd), (ins DPR:$Ddin, DPR:$Dn, DPR:$Dm),
@@ -1845,9 +1908,10 @@ def VNMLAS : ASbI<0b11100, 0b01, 1, 0,
}
def VNMLAH : AHbI<0b11100, 0b01, 1, 0,
- (outs SPR:$Sd), (ins SPR:$Sdin, SPR:$Sn, SPR:$Sm),
+ (outs HPR:$Sd), (ins HPR:$Sdin, HPR:$Sn, HPR:$Sm),
IIC_fpMAC16, "vnmla", ".f16\t$Sd, $Sn, $Sm",
- []>,
+ [(set HPR:$Sd, (fsub_mlx (fneg (fmul_su HPR:$Sn, HPR:$Sm)),
+ HPR:$Sdin))]>,
RegConstraint<"$Sdin = $Sd">,
Requires<[HasFullFP16,UseFPVMLx,DontUseFusedMAC]>;
@@ -1858,6 +1922,9 @@ def : Pat<(fsub_mlx (fneg (fmul_su DPR:$a, (f64 DPR:$b))), DPR:$dstin),
def : Pat<(fsub_mlx (fneg (fmul_su SPR:$a, SPR:$b)), SPR:$dstin),
(VNMLAS SPR:$dstin, SPR:$a, SPR:$b)>,
Requires<[HasVFP2,DontUseNEONForFP,UseFPVMLx,DontUseFusedMAC]>;
+def : Pat<(fsub_mlx (fneg (fmul_su HPR:$a, HPR:$b)), HPR:$dstin),
+ (VNMLAH HPR:$dstin, HPR:$a, HPR:$b)>,
+ Requires<[HasFullFP16,DontUseNEONForFP,UseFPVMLx,DontUseFusedMAC]>;
// (-dst - (a * b)) -> -(dst + (a * b))
def : Pat<(fsub_mlx (fneg DPR:$dstin), (fmul_su DPR:$a, (f64 DPR:$b))),
@@ -1866,6 +1933,9 @@ def : Pat<(fsub_mlx (fneg DPR:$dstin), (fmul_su DPR:$a, (f64 DPR:$b))),
def : Pat<(fsub_mlx (fneg SPR:$dstin), (fmul_su SPR:$a, SPR:$b)),
(VNMLAS SPR:$dstin, SPR:$a, SPR:$b)>,
Requires<[HasVFP2,DontUseNEONForFP,UseFPVMLx,DontUseFusedMAC]>;
+def : Pat<(fsub_mlx (fneg HPR:$dstin), (fmul_su HPR:$a, HPR:$b)),
+ (VNMLAH HPR:$dstin, HPR:$a, HPR:$b)>,
+ Requires<[HasFullFP16,DontUseNEONForFP,UseFPVMLx,DontUseFusedMAC]>;
def VNMLSD : ADbI<0b11100, 0b01, 0, 0,
(outs DPR:$Dd), (ins DPR:$Ddin, DPR:$Dn, DPR:$Dm),
@@ -1889,9 +1959,9 @@ def VNMLSS : ASbI<0b11100, 0b01, 0, 0,
}
def VNMLSH : AHbI<0b11100, 0b01, 0, 0,
- (outs SPR:$Sd), (ins SPR:$Sdin, SPR:$Sn, SPR:$Sm),
+ (outs HPR:$Sd), (ins HPR:$Sdin, HPR:$Sn, HPR:$Sm),
IIC_fpMAC16, "vnmls", ".f16\t$Sd, $Sn, $Sm",
- []>,
+ [(set HPR:$Sd, (fsub_mlx (fmul_su HPR:$Sn, HPR:$Sm), HPR:$Sdin))]>,
RegConstraint<"$Sdin = $Sd">,
Requires<[HasFullFP16,UseFPVMLx,DontUseFusedMAC]>;
@@ -1901,6 +1971,9 @@ def : Pat<(fsub_mlx (fmul_su DPR:$a, (f64 DPR:$b)), DPR:$dstin),
def : Pat<(fsub_mlx (fmul_su SPR:$a, SPR:$b), SPR:$dstin),
(VNMLSS SPR:$dstin, SPR:$a, SPR:$b)>,
Requires<[HasVFP2,DontUseNEONForFP,UseFPVMLx,DontUseFusedMAC]>;
+def : Pat<(fsub_mlx (fmul_su HPR:$a, HPR:$b), HPR:$dstin),
+ (VNMLSH HPR:$dstin, HPR:$a, HPR:$b)>,
+ Requires<[HasFullFP16,DontUseNEONForFP,UseFPVMLx,DontUseFusedMAC]>;
//===----------------------------------------------------------------------===//
// Fused FP Multiply-Accumulate Operations.
@@ -1927,9 +2000,10 @@ def VFMAS : ASbIn<0b11101, 0b10, 0, 0,
}
def VFMAH : AHbI<0b11101, 0b10, 0, 0,
- (outs SPR:$Sd), (ins SPR:$Sdin, SPR:$Sn, SPR:$Sm),
+ (outs HPR:$Sd), (ins HPR:$Sdin, HPR:$Sn, HPR:$Sm),
IIC_fpFMAC16, "vfma", ".f16\t$Sd, $Sn, $Sm",
- []>,
+ [(set HPR:$Sd, (fadd_mlx (fmul_su HPR:$Sn, HPR:$Sm),
+ HPR:$Sdin))]>,
RegConstraint<"$Sdin = $Sd">,
Requires<[HasFullFP16,UseFusedMAC]>,
Sched<[WriteFPMAC32, ReadFPMAC, ReadFPMUL, ReadFPMUL]>;
@@ -1940,6 +2014,9 @@ def : Pat<(fadd_mlx DPR:$dstin, (fmul_su DPR:$a, (f64 DPR:$b))),
def : Pat<(fadd_mlx SPR:$dstin, (fmul_su SPR:$a, SPR:$b)),
(VFMAS SPR:$dstin, SPR:$a, SPR:$b)>,
Requires<[HasVFP4,DontUseNEONForFP,UseFusedMAC]>;
+def : Pat<(fadd_mlx HPR:$dstin, (fmul_su HPR:$a, HPR:$b)),
+ (VFMAH HPR:$dstin, HPR:$a, HPR:$b)>,
+ Requires<[HasFullFP16,DontUseNEONForFP,UseFusedMAC]>;
// Match @llvm.fma.* intrinsics
// (fma x, y, z) -> (vfms z, x, y)
@@ -1972,9 +2049,10 @@ def VFMSS : ASbIn<0b11101, 0b10, 1, 0,
}
def VFMSH : AHbI<0b11101, 0b10, 1, 0,
- (outs SPR:$Sd), (ins SPR:$Sdin, SPR:$Sn, SPR:$Sm),
+ (outs HPR:$Sd), (ins HPR:$Sdin, HPR:$Sn, HPR:$Sm),
IIC_fpFMAC16, "vfms", ".f16\t$Sd, $Sn, $Sm",
- []>,
+ [(set HPR:$Sd, (fadd_mlx (fneg (fmul_su HPR:$Sn, HPR:$Sm)),
+ HPR:$Sdin))]>,
RegConstraint<"$Sdin = $Sd">,
Requires<[HasFullFP16,UseFusedMAC]>,
Sched<[WriteFPMAC32, ReadFPMAC, ReadFPMUL, ReadFPMUL]>;
@@ -1985,6 +2063,9 @@ def : Pat<(fsub_mlx DPR:$dstin, (fmul_su DPR:$a, (f64 DPR:$b))),
def : Pat<(fsub_mlx SPR:$dstin, (fmul_su SPR:$a, SPR:$b)),
(VFMSS SPR:$dstin, SPR:$a, SPR:$b)>,
Requires<[HasVFP4,DontUseNEONForFP,UseFusedMAC]>;
+def : Pat<(fsub_mlx HPR:$dstin, (fmul_su HPR:$a, HPR:$b)),
+ (VFMSH HPR:$dstin, HPR:$a, HPR:$b)>,
+ Requires<[HasFullFP16,DontUseNEONForFP,UseFusedMAC]>;
// Match @llvm.fma.* intrinsics
// (fma (fneg x), y, z) -> (vfms z, x, y)
@@ -2024,9 +2105,10 @@ def VFNMAS : ASbI<0b11101, 0b01, 1, 0,
}
def VFNMAH : AHbI<0b11101, 0b01, 1, 0,
- (outs SPR:$Sd), (ins SPR:$Sdin, SPR:$Sn, SPR:$Sm),
+ (outs HPR:$Sd), (ins HPR:$Sdin, HPR:$Sn, HPR:$Sm),
IIC_fpFMAC16, "vfnma", ".f16\t$Sd, $Sn, $Sm",
- []>,
+ [(set HPR:$Sd, (fsub_mlx (fneg (fmul_su HPR:$Sn, HPR:$Sm)),
+ HPR:$Sdin))]>,
RegConstraint<"$Sdin = $Sd">,
Requires<[HasFullFP16,UseFusedMAC]>,
Sched<[WriteFPMAC32, ReadFPMAC, ReadFPMUL, ReadFPMUL]>;
@@ -2075,9 +2157,9 @@ def VFNMSS : ASbI<0b11101, 0b01, 0, 0,
}
def VFNMSH : AHbI<0b11101, 0b01, 0, 0,
- (outs SPR:$Sd), (ins SPR:$Sdin, SPR:$Sn, SPR:$Sm),
+ (outs HPR:$Sd), (ins HPR:$Sdin, HPR:$Sn, HPR:$Sm),
IIC_fpFMAC16, "vfnms", ".f16\t$Sd, $Sn, $Sm",
- []>,
+ [(set HPR:$Sd, (fsub_mlx (fmul_su HPR:$Sn, HPR:$Sm), HPR:$Sdin))]>,
RegConstraint<"$Sdin = $Sd">,
Requires<[HasFullFP16,UseFusedMAC]>,
Sched<[WriteFPMAC32, ReadFPMAC, ReadFPMUL, ReadFPMUL]>;
@@ -2269,10 +2351,11 @@ def FCONSTS : VFPAI<(outs SPR:$Sd), (ins vfp_f32imm:$imm),
let Inst{3-0} = imm{3-0};
}
-def FCONSTH : VFPAI<(outs SPR:$Sd), (ins vfp_f16imm:$imm),
+def FCONSTH : VFPAI<(outs HPR:$Sd), (ins vfp_f16imm:$imm),
VFPMiscFrm, IIC_fpUNA16,
"vmov", ".f16\t$Sd, $imm",
- []>, Requires<[HasFullFP16]> {
+ [(set HPR:$Sd, vfp_f16imm:$imm)]>,
+ Requires<[HasFullFP16]> {
bits<5> Sd;
bits<8> imm;
diff --git a/lib/Target/ARM/ARMInstructionSelector.cpp b/lib/Target/ARM/ARMInstructionSelector.cpp
index b0fd0b476920..6692a4d41420 100644
--- a/lib/Target/ARM/ARMInstructionSelector.cpp
+++ b/lib/Target/ARM/ARMInstructionSelector.cpp
@@ -117,39 +117,47 @@ ARMInstructionSelector::ARMInstructionSelector(const ARMBaseTargetMachine &TM,
{
}
-static bool selectCopy(MachineInstr &I, const TargetInstrInfo &TII,
- MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI,
- const RegisterBankInfo &RBI) {
- unsigned DstReg = I.getOperand(0).getReg();
- if (TargetRegisterInfo::isPhysicalRegister(DstReg))
- return true;
-
- const RegisterBank *RegBank = RBI.getRegBank(DstReg, MRI, TRI);
- (void)RegBank;
+static const TargetRegisterClass *guessRegClass(unsigned Reg,
+ MachineRegisterInfo &MRI,
+ const TargetRegisterInfo &TRI,
+ const RegisterBankInfo &RBI) {
+ const RegisterBank *RegBank = RBI.getRegBank(Reg, MRI, TRI);
assert(RegBank && "Can't get reg bank for virtual register");
- const unsigned DstSize = MRI.getType(DstReg).getSizeInBits();
+ const unsigned Size = MRI.getType(Reg).getSizeInBits();
assert((RegBank->getID() == ARM::GPRRegBankID ||
RegBank->getID() == ARM::FPRRegBankID) &&
"Unsupported reg bank");
- const TargetRegisterClass *RC = &ARM::GPRRegClass;
-
if (RegBank->getID() == ARM::FPRRegBankID) {
- if (DstSize == 32)
- RC = &ARM::SPRRegClass;
- else if (DstSize == 64)
- RC = &ARM::DPRRegClass;
+ if (Size == 32)
+ return &ARM::SPRRegClass;
+ else if (Size == 64)
+ return &ARM::DPRRegClass;
+ else if (Size == 128)
+ return &ARM::QPRRegClass;
else
llvm_unreachable("Unsupported destination size");
}
+ return &ARM::GPRRegClass;
+}
+
+static bool selectCopy(MachineInstr &I, const TargetInstrInfo &TII,
+ MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI,
+ const RegisterBankInfo &RBI) {
+ unsigned DstReg = I.getOperand(0).getReg();
+ if (TargetRegisterInfo::isPhysicalRegister(DstReg))
+ return true;
+
+ const TargetRegisterClass *RC = guessRegClass(DstReg, MRI, TRI, RBI);
+
// No need to constrain SrcReg. It will get constrained when
// we hit another of its uses or its defs.
// Copies do not have constraints.
if (!RBI.constrainGenericRegister(DstReg, *RC, MRI)) {
- DEBUG(dbgs() << "Failed to constrain " << TII.getName(I.getOpcode())
- << " operand\n");
+ LLVM_DEBUG(dbgs() << "Failed to constrain " << TII.getName(I.getOpcode())
+ << " operand\n");
return false;
}
return true;
@@ -393,12 +401,12 @@ bool ARMInstructionSelector::validReg(MachineRegisterInfo &MRI, unsigned Reg,
unsigned ExpectedSize,
unsigned ExpectedRegBankID) const {
if (MRI.getType(Reg).getSizeInBits() != ExpectedSize) {
- DEBUG(dbgs() << "Unexpected size for register");
+ LLVM_DEBUG(dbgs() << "Unexpected size for register");
return false;
}
if (RBI.getRegBank(Reg, MRI, TRI)->getID() != ExpectedRegBankID) {
- DEBUG(dbgs() << "Unexpected register bank for register");
+ LLVM_DEBUG(dbgs() << "Unexpected register bank for register");
return false;
}
@@ -490,13 +498,13 @@ bool ARMInstructionSelector::insertComparison(CmpConstants Helper, InsertInfo I,
bool ARMInstructionSelector::selectGlobal(MachineInstrBuilder &MIB,
MachineRegisterInfo &MRI) const {
if ((STI.isROPI() || STI.isRWPI()) && !STI.isTargetELF()) {
- DEBUG(dbgs() << "ROPI and RWPI only supported for ELF\n");
+ LLVM_DEBUG(dbgs() << "ROPI and RWPI only supported for ELF\n");
return false;
}
auto GV = MIB->getOperand(1).getGlobal();
if (GV->isThreadLocal()) {
- DEBUG(dbgs() << "TLS variables not supported yet\n");
+ LLVM_DEBUG(dbgs() << "TLS variables not supported yet\n");
return false;
}
@@ -505,7 +513,7 @@ bool ARMInstructionSelector::selectGlobal(MachineInstrBuilder &MIB,
bool UseMovt = STI.useMovt(MF);
- unsigned Size = TM.getPointerSize();
+ unsigned Size = TM.getPointerSize(0);
unsigned Alignment = 4;
auto addOpsForConstantPoolLoad = [&MF, Alignment,
@@ -548,7 +556,7 @@ bool ARMInstructionSelector::selectGlobal(MachineInstrBuilder &MIB,
if (Indirect)
MIB.addMemOperand(MF.getMachineMemOperand(
MachinePointerInfo::getGOT(MF), MachineMemOperand::MOLoad,
- TM.getPointerSize(), Alignment));
+ TM.getProgramPointerSize(), Alignment));
return constrainSelectedInstRegOperands(*MIB, TII, TRI, RBI);
}
@@ -601,7 +609,7 @@ bool ARMInstructionSelector::selectGlobal(MachineInstrBuilder &MIB,
else
MIB->setDesc(TII.get(ARM::LDRLIT_ga_abs));
} else {
- DEBUG(dbgs() << "Object format not supported yet\n");
+ LLVM_DEBUG(dbgs() << "Object format not supported yet\n");
return false;
}
@@ -670,14 +678,6 @@ bool ARMInstructionSelector::select(MachineInstr &I,
}
using namespace TargetOpcode;
- if (I.getOpcode() == G_CONSTANT) {
- // Pointer constants should be treated the same as 32-bit integer constants.
- // Change the type and let TableGen handle it.
- unsigned ResultReg = I.getOperand(0).getReg();
- LLT Ty = MRI.getType(ResultReg);
- if (Ty.isPointer())
- MRI.setType(ResultReg, LLT::scalar(32));
- }
if (selectImpl(I, CoverageInfo))
return true;
@@ -693,7 +693,7 @@ bool ARMInstructionSelector::select(MachineInstr &I,
LLT DstTy = MRI.getType(I.getOperand(0).getReg());
// FIXME: Smaller destination sizes coming soon!
if (DstTy.getSizeInBits() != 32) {
- DEBUG(dbgs() << "Unsupported destination size for extension");
+ LLVM_DEBUG(dbgs() << "Unsupported destination size for extension");
return false;
}
@@ -735,7 +735,7 @@ bool ARMInstructionSelector::select(MachineInstr &I,
break;
}
default:
- DEBUG(dbgs() << "Unsupported source size for extension");
+ LLVM_DEBUG(dbgs() << "Unsupported source size for extension");
return false;
}
break;
@@ -776,18 +776,45 @@ bool ARMInstructionSelector::select(MachineInstr &I,
}
if (SrcRegBank.getID() != DstRegBank.getID()) {
- DEBUG(dbgs() << "G_TRUNC/G_ANYEXT operands on different register banks\n");
+ LLVM_DEBUG(
+ dbgs() << "G_TRUNC/G_ANYEXT operands on different register banks\n");
return false;
}
if (SrcRegBank.getID() != ARM::GPRRegBankID) {
- DEBUG(dbgs() << "G_TRUNC/G_ANYEXT on non-GPR not supported yet\n");
+ LLVM_DEBUG(dbgs() << "G_TRUNC/G_ANYEXT on non-GPR not supported yet\n");
return false;
}
I.setDesc(TII.get(COPY));
return selectCopy(I, TII, MRI, TRI, RBI);
}
+ case G_CONSTANT: {
+ if (!MRI.getType(I.getOperand(0).getReg()).isPointer()) {
+ // Non-pointer constants should be handled by TableGen.
+ LLVM_DEBUG(dbgs() << "Unsupported constant type\n");
+ return false;
+ }
+
+ auto &Val = I.getOperand(1);
+ if (Val.isCImm()) {
+ if (!Val.getCImm()->isZero()) {
+ LLVM_DEBUG(dbgs() << "Unsupported pointer constant value\n");
+ return false;
+ }
+ Val.ChangeToImmediate(0);
+ } else {
+ assert(Val.isImm() && "Unexpected operand for G_CONSTANT");
+ if (Val.getImm() != 0) {
+ LLVM_DEBUG(dbgs() << "Unsupported pointer constant value\n");
+ return false;
+ }
+ }
+
+ I.setDesc(TII.get(ARM::MOVi));
+ MIB.add(predOps(ARMCC::AL)).add(condCodeOp());
+ break;
+ }
case G_INTTOPTR:
case G_PTRTOINT: {
auto SrcReg = I.getOperand(1).getReg();
@@ -797,13 +824,15 @@ bool ARMInstructionSelector::select(MachineInstr &I,
const auto &DstRegBank = *RBI.getRegBank(DstReg, MRI, TRI);
if (SrcRegBank.getID() != DstRegBank.getID()) {
- DEBUG(dbgs()
- << "G_INTTOPTR/G_PTRTOINT operands on different register banks\n");
+ LLVM_DEBUG(
+ dbgs()
+ << "G_INTTOPTR/G_PTRTOINT operands on different register banks\n");
return false;
}
if (SrcRegBank.getID() != ARM::GPRRegBankID) {
- DEBUG(dbgs() << "G_INTTOPTR/G_PTRTOINT on non-GPR not supported yet\n");
+ LLVM_DEBUG(
+ dbgs() << "G_INTTOPTR/G_PTRTOINT on non-GPR not supported yet\n");
return false;
}
@@ -824,11 +853,11 @@ bool ARMInstructionSelector::select(MachineInstr &I,
unsigned Size = MRI.getType(OpReg).getSizeInBits();
if (Size == 64 && STI.isFPOnlySP()) {
- DEBUG(dbgs() << "Subtarget only supports single precision");
+ LLVM_DEBUG(dbgs() << "Subtarget only supports single precision");
return false;
}
if (Size != 32 && Size != 64) {
- DEBUG(dbgs() << "Unsupported size for G_FCMP operand");
+ LLVM_DEBUG(dbgs() << "Unsupported size for G_FCMP operand");
return false;
}
@@ -859,7 +888,7 @@ bool ARMInstructionSelector::select(MachineInstr &I,
case G_LOAD: {
const auto &MemOp = **I.memoperands_begin();
if (MemOp.getOrdering() != AtomicOrdering::NotAtomic) {
- DEBUG(dbgs() << "Atomic load/store not supported yet\n");
+ LLVM_DEBUG(dbgs() << "Atomic load/store not supported yet\n");
return false;
}
@@ -896,7 +925,7 @@ bool ARMInstructionSelector::select(MachineInstr &I,
}
case G_BRCOND: {
if (!validReg(MRI, I.getOperand(0).getReg(), 1, ARM::GPRRegBankID)) {
- DEBUG(dbgs() << "Unsupported condition register for G_BRCOND");
+ LLVM_DEBUG(dbgs() << "Unsupported condition register for G_BRCOND");
return false;
}
@@ -917,6 +946,17 @@ bool ARMInstructionSelector::select(MachineInstr &I,
I.eraseFromParent();
return true;
}
+ case G_PHI: {
+ I.setDesc(TII.get(PHI));
+
+ unsigned DstReg = I.getOperand(0).getReg();
+ const TargetRegisterClass *RC = guessRegClass(DstReg, MRI, TRI, RBI);
+ if (!RBI.constrainGenericRegister(DstReg, *RC, MRI)) {
+ break;
+ }
+
+ return true;
+ }
default:
return false;
}
diff --git a/lib/Target/ARM/ARMLegalizerInfo.cpp b/lib/Target/ARM/ARMLegalizerInfo.cpp
index 8cff1f0869d0..891418306903 100644
--- a/lib/Target/ARM/ARMLegalizerInfo.cpp
+++ b/lib/Target/ARM/ARMLegalizerInfo.cpp
@@ -23,6 +23,7 @@
#include "llvm/IR/Type.h"
using namespace llvm;
+using namespace LegalizeActions;
/// FIXME: The following static functions are SizeChangeStrategy functions
/// that are meant to temporarily mimic the behaviour of the old legalization
@@ -40,7 +41,7 @@ addAndInterleaveWithUnsupported(LegalizerInfo::SizeAndActionsVec &result,
result.push_back(v[i]);
if (i + 1 < v[i].first && i + 1 < v.size() &&
v[i + 1].first != v[i].first + 1)
- result.push_back({v[i].first + 1, LegalizerInfo::Unsupported});
+ result.push_back({v[i].first + 1, Unsupported});
}
}
@@ -48,27 +49,14 @@ static LegalizerInfo::SizeAndActionsVec
widen_8_16(const LegalizerInfo::SizeAndActionsVec &v) {
assert(v.size() >= 1);
assert(v[0].first > 17);
- LegalizerInfo::SizeAndActionsVec result = {
- {1, LegalizerInfo::Unsupported},
- {8, LegalizerInfo::WidenScalar}, {9, LegalizerInfo::Unsupported},
- {16, LegalizerInfo::WidenScalar}, {17, LegalizerInfo::Unsupported}};
+ LegalizerInfo::SizeAndActionsVec result = {{1, Unsupported},
+ {8, WidenScalar},
+ {9, Unsupported},
+ {16, WidenScalar},
+ {17, Unsupported}};
addAndInterleaveWithUnsupported(result, v);
auto Largest = result.back().first;
- result.push_back({Largest + 1, LegalizerInfo::Unsupported});
- return result;
-}
-
-static LegalizerInfo::SizeAndActionsVec
-widen_1_8_16(const LegalizerInfo::SizeAndActionsVec &v) {
- assert(v.size() >= 1);
- assert(v[0].first > 17);
- LegalizerInfo::SizeAndActionsVec result = {
- {1, LegalizerInfo::WidenScalar}, {2, LegalizerInfo::Unsupported},
- {8, LegalizerInfo::WidenScalar}, {9, LegalizerInfo::Unsupported},
- {16, LegalizerInfo::WidenScalar}, {17, LegalizerInfo::Unsupported}};
- addAndInterleaveWithUnsupported(result, v);
- auto Largest = result.back().first;
- result.push_back({Largest + 1, LegalizerInfo::Unsupported});
+ result.push_back({Largest + 1, Unsupported});
return result;
}
@@ -87,30 +75,21 @@ ARMLegalizerInfo::ARMLegalizerInfo(const ARMSubtarget &ST) {
const LLT s32 = LLT::scalar(32);
const LLT s64 = LLT::scalar(64);
- setAction({G_GLOBAL_VALUE, p0}, Legal);
- setAction({G_FRAME_INDEX, p0}, Legal);
+ getActionDefinitionsBuilder(G_GLOBAL_VALUE).legalFor({p0});
+ getActionDefinitionsBuilder(G_FRAME_INDEX).legalFor({p0});
- for (unsigned Op : {G_LOAD, G_STORE}) {
- for (auto Ty : {s1, s8, s16, s32, p0})
- setAction({Op, Ty}, Legal);
- setAction({Op, 1, p0}, Legal);
- }
-
- for (unsigned Op : {G_ADD, G_SUB, G_MUL, G_AND, G_OR, G_XOR}) {
- if (Op != G_ADD)
- setLegalizeScalarToDifferentSizeStrategy(
- Op, 0, widenToLargerTypesUnsupportedOtherwise);
- setAction({Op, s32}, Legal);
- }
+ getActionDefinitionsBuilder({G_ADD, G_SUB, G_MUL, G_AND, G_OR, G_XOR})
+ .legalFor({s32})
+ .minScalar(0, s32);
- for (unsigned Op : {G_SDIV, G_UDIV}) {
- setLegalizeScalarToDifferentSizeStrategy(Op, 0,
- widenToLargerTypesUnsupportedOtherwise);
- if (ST.hasDivideInARMMode())
- setAction({Op, s32}, Legal);
- else
- setAction({Op, s32}, Libcall);
- }
+ if (ST.hasDivideInARMMode())
+ getActionDefinitionsBuilder({G_SDIV, G_UDIV})
+ .legalFor({s32})
+ .clampScalar(0, s32, s32);
+ else
+ getActionDefinitionsBuilder({G_SDIV, G_UDIV})
+ .libcallFor({s32})
+ .clampScalar(0, s32, s32);
for (unsigned Op : {G_SREM, G_UREM}) {
setLegalizeScalarToDifferentSizeStrategy(Op, 0, widen_8_16);
@@ -122,74 +101,96 @@ ARMLegalizerInfo::ARMLegalizerInfo(const ARMSubtarget &ST) {
setAction({Op, s32}, Libcall);
}
- for (unsigned Op : {G_SEXT, G_ZEXT, G_ANYEXT}) {
- setAction({Op, s32}, Legal);
- }
+ getActionDefinitionsBuilder({G_SEXT, G_ZEXT, G_ANYEXT})
+ .legalForCartesianProduct({s32}, {s1, s8, s16});
+
+ getActionDefinitionsBuilder(G_INTTOPTR).legalFor({{p0, s32}});
+ getActionDefinitionsBuilder(G_PTRTOINT).legalFor({{s32, p0}});
- setAction({G_INTTOPTR, p0}, Legal);
- setAction({G_INTTOPTR, 1, s32}, Legal);
+ getActionDefinitionsBuilder({G_ASHR, G_LSHR, G_SHL}).legalFor({s32});
- setAction({G_PTRTOINT, s32}, Legal);
- setAction({G_PTRTOINT, 1, p0}, Legal);
+ getActionDefinitionsBuilder(G_GEP).legalFor({{p0, s32}});
- for (unsigned Op : {G_ASHR, G_LSHR, G_SHL})
- setAction({Op, s32}, Legal);
+ getActionDefinitionsBuilder(G_SELECT).legalForCartesianProduct({s32, p0},
+ {s1});
- setAction({G_GEP, p0}, Legal);
- setAction({G_GEP, 1, s32}, Legal);
+ getActionDefinitionsBuilder(G_BRCOND).legalFor({s1});
- setAction({G_SELECT, s32}, Legal);
- setAction({G_SELECT, p0}, Legal);
- setAction({G_SELECT, 1, s1}, Legal);
+ getActionDefinitionsBuilder(G_CONSTANT)
+ .legalFor({s32, p0})
+ .clampScalar(0, s32, s32);
- setAction({G_BRCOND, s1}, Legal);
+ getActionDefinitionsBuilder(G_ICMP)
+ .legalForCartesianProduct({s1}, {s32, p0})
+ .minScalar(1, s32);
- setAction({G_CONSTANT, s32}, Legal);
- setAction({G_CONSTANT, p0}, Legal);
- setLegalizeScalarToDifferentSizeStrategy(G_CONSTANT, 0, widen_1_8_16);
+ // We're keeping these builders around because we'll want to add support for
+ // floating point to them.
+ auto &LoadStoreBuilder =
+ getActionDefinitionsBuilder({G_LOAD, G_STORE})
+ .legalForCartesianProduct({s1, s8, s16, s32, p0}, {p0});
- setAction({G_ICMP, s1}, Legal);
- setLegalizeScalarToDifferentSizeStrategy(G_ICMP, 1,
- widenToLargerTypesUnsupportedOtherwise);
- for (auto Ty : {s32, p0})
- setAction({G_ICMP, 1, Ty}, Legal);
+ auto &PhiBuilder =
+ getActionDefinitionsBuilder(G_PHI).legalFor({s32, p0}).minScalar(0, s32);
if (!ST.useSoftFloat() && ST.hasVFP2()) {
- for (unsigned BinOp : {G_FADD, G_FSUB, G_FMUL, G_FDIV})
- for (auto Ty : {s32, s64})
- setAction({BinOp, Ty}, Legal);
+ getActionDefinitionsBuilder(
+ {G_FADD, G_FSUB, G_FMUL, G_FDIV, G_FCONSTANT, G_FNEG})
+ .legalFor({s32, s64});
+
+ LoadStoreBuilder.legalFor({{s64, p0}});
+ PhiBuilder.legalFor({s64});
+
+ getActionDefinitionsBuilder(G_FCMP).legalForCartesianProduct({s1},
+ {s32, s64});
- setAction({G_LOAD, s64}, Legal);
- setAction({G_STORE, s64}, Legal);
+ getActionDefinitionsBuilder(G_MERGE_VALUES).legalFor({{s64, s32}});
+ getActionDefinitionsBuilder(G_UNMERGE_VALUES).legalFor({{s32, s64}});
- setAction({G_FCMP, s1}, Legal);
- setAction({G_FCMP, 1, s32}, Legal);
- setAction({G_FCMP, 1, s64}, Legal);
+ getActionDefinitionsBuilder(G_FPEXT).legalFor({{s64, s32}});
+ getActionDefinitionsBuilder(G_FPTRUNC).legalFor({{s32, s64}});
- setAction({G_MERGE_VALUES, s64}, Legal);
- setAction({G_MERGE_VALUES, 1, s32}, Legal);
- setAction({G_UNMERGE_VALUES, s32}, Legal);
- setAction({G_UNMERGE_VALUES, 1, s64}, Legal);
+ getActionDefinitionsBuilder({G_FPTOSI, G_FPTOUI})
+ .legalForCartesianProduct({s32}, {s32, s64});
+ getActionDefinitionsBuilder({G_SITOFP, G_UITOFP})
+ .legalForCartesianProduct({s32, s64}, {s32});
} else {
- for (unsigned BinOp : {G_FADD, G_FSUB, G_FMUL, G_FDIV})
- for (auto Ty : {s32, s64})
- setAction({BinOp, Ty}, Libcall);
+ getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV})
+ .libcallFor({s32, s64});
+
+ LoadStoreBuilder.maxScalar(0, s32);
+
+ for (auto Ty : {s32, s64})
+ setAction({G_FNEG, Ty}, Lower);
- setAction({G_FCMP, s1}, Legal);
- setAction({G_FCMP, 1, s32}, Custom);
- setAction({G_FCMP, 1, s64}, Custom);
+ getActionDefinitionsBuilder(G_FCONSTANT).customFor({s32, s64});
+
+ getActionDefinitionsBuilder(G_FCMP).customForCartesianProduct({s1},
+ {s32, s64});
if (AEABI(ST))
setFCmpLibcallsAEABI();
else
setFCmpLibcallsGNU();
+
+ getActionDefinitionsBuilder(G_FPEXT).libcallFor({{s64, s32}});
+ getActionDefinitionsBuilder(G_FPTRUNC).libcallFor({{s32, s64}});
+
+ getActionDefinitionsBuilder({G_FPTOSI, G_FPTOUI})
+ .libcallForCartesianProduct({s32}, {s32, s64});
+ getActionDefinitionsBuilder({G_SITOFP, G_UITOFP})
+ .libcallForCartesianProduct({s32, s64}, {s32});
}
- for (unsigned Op : {G_FREM, G_FPOW})
- for (auto Ty : {s32, s64})
- setAction({Op, Ty}, Libcall);
+ if (!ST.useSoftFloat() && ST.hasVFP4())
+ getActionDefinitionsBuilder(G_FMA).legalFor({s32, s64});
+ else
+ getActionDefinitionsBuilder(G_FMA).libcallFor({s32, s64});
+
+ getActionDefinitionsBuilder({G_FREM, G_FPOW}).libcallFor({s32, s64});
computeTables();
+ verify(*ST.getInstrInfo());
}
void ARMLegalizerInfo::setFCmpLibcallsAEABI() {
@@ -305,6 +306,7 @@ bool ARMLegalizerInfo::legalizeCustom(MachineInstr &MI,
using namespace TargetOpcode;
MIRBuilder.setInstr(MI);
+ LLVMContext &Ctx = MIRBuilder.getMF().getFunction().getContext();
switch (MI.getOpcode()) {
default:
@@ -321,7 +323,6 @@ bool ARMLegalizerInfo::legalizeCustom(MachineInstr &MI,
// Our divmod libcalls return a struct containing the quotient and the
// remainder. We need to create a virtual register for it.
- auto &Ctx = MIRBuilder.getMF().getFunction().getContext();
Type *ArgTy = Type::getInt32Ty(Ctx);
StructType *RetTy = StructType::get(Ctx, {ArgTy, ArgTy}, /* Packed */ true);
auto RetVal = MRI.createGenericVirtualRegister(
@@ -362,7 +363,6 @@ bool ARMLegalizerInfo::legalizeCustom(MachineInstr &MI,
return true;
}
- auto &Ctx = MIRBuilder.getMF().getFunction().getContext();
assert((OpSize == 32 || OpSize == 64) && "Unsupported operand size");
auto *ArgTy = OpSize == 32 ? Type::getFloatTy(Ctx) : Type::getDoubleTy(Ctx);
auto *RetTy = Type::getInt32Ty(Ctx);
@@ -407,6 +407,14 @@ bool ARMLegalizerInfo::legalizeCustom(MachineInstr &MI,
}
break;
}
+ case G_FCONSTANT: {
+ // Convert to integer constants, while preserving the binary representation.
+ auto AsInteger =
+ MI.getOperand(1).getFPImm()->getValueAPF().bitcastToAPInt();
+ MIRBuilder.buildConstant(MI.getOperand(0).getReg(),
+ *ConstantInt::get(Ctx, AsInteger));
+ break;
+ }
}
MI.eraseFromParent();
diff --git a/lib/Target/ARM/ARMLoadStoreOptimizer.cpp b/lib/Target/ARM/ARMLoadStoreOptimizer.cpp
index 8b3a2e223796..901138dbdfd5 100644
--- a/lib/Target/ARM/ARMLoadStoreOptimizer.cpp
+++ b/lib/Target/ARM/ARMLoadStoreOptimizer.cpp
@@ -1198,7 +1198,7 @@ findIncDecBefore(MachineBasicBlock::iterator MBBI, unsigned Reg,
// Skip debug values.
MachineBasicBlock::iterator PrevMBBI = std::prev(MBBI);
- while (PrevMBBI->isDebugValue() && PrevMBBI != BeginMBBI)
+ while (PrevMBBI->isDebugInstr() && PrevMBBI != BeginMBBI)
--PrevMBBI;
Offset = isIncrementOrDecrement(*PrevMBBI, Reg, Pred, PredReg);
@@ -1214,7 +1214,7 @@ findIncDecAfter(MachineBasicBlock::iterator MBBI, unsigned Reg,
MachineBasicBlock::iterator EndMBBI = MBB.end();
MachineBasicBlock::iterator NextMBBI = std::next(MBBI);
// Skip debug values.
- while (NextMBBI != EndMBBI && NextMBBI->isDebugValue())
+ while (NextMBBI != EndMBBI && NextMBBI->isDebugInstr())
++NextMBBI;
if (NextMBBI == EndMBBI)
return EndMBBI;
@@ -1807,7 +1807,7 @@ bool ARMLoadStoreOpt::LoadStoreMultipleOpti(MachineBasicBlock &MBB) {
MBBI = I;
--Position;
// Fallthrough to look into existing chain.
- } else if (MBBI->isDebugValue()) {
+ } else if (MBBI->isDebugInstr()) {
continue;
} else if (MBBI->getOpcode() == ARM::t2LDRDi8 ||
MBBI->getOpcode() == ARM::t2STRDi8) {
@@ -1834,7 +1834,7 @@ bool ARMLoadStoreOpt::LoadStoreMultipleOpti(MachineBasicBlock &MBB) {
auto LessThan = [](const MergeCandidate* M0, const MergeCandidate *M1) {
return M0->InsertPos < M1->InsertPos;
};
- std::sort(Candidates.begin(), Candidates.end(), LessThan);
+ llvm::sort(Candidates.begin(), Candidates.end(), LessThan);
// Go through list of candidates and merge.
bool Changed = false;
@@ -1891,8 +1891,8 @@ bool ARMLoadStoreOpt::MergeReturnIntoLDM(MachineBasicBlock &MBB) {
MBBI->getOpcode() == ARM::tBX_RET ||
MBBI->getOpcode() == ARM::MOVPCLR)) {
MachineBasicBlock::iterator PrevI = std::prev(MBBI);
- // Ignore any DBG_VALUE instructions.
- while (PrevI->isDebugValue() && PrevI != MBB.begin())
+ // Ignore any debug instructions.
+ while (PrevI->isDebugInstr() && PrevI != MBB.begin())
--PrevI;
MachineInstr &PrevMI = *PrevI;
unsigned Opcode = PrevMI.getOpcode();
@@ -2063,7 +2063,7 @@ static bool IsSafeAndProfitableToMove(bool isLd, unsigned Base,
// Are there stores / loads / calls between them?
SmallSet<unsigned, 4> AddedRegPressure;
while (++I != E) {
- if (I->isDebugValue() || MemOps.count(&*I))
+ if (I->isDebugInstr() || MemOps.count(&*I))
continue;
if (I->isCall() || I->isTerminator() || I->hasUnmodeledSideEffects())
return false;
@@ -2172,13 +2172,13 @@ bool ARMPreAllocLoadStoreOpt::RescheduleOps(MachineBasicBlock *MBB,
bool RetVal = false;
// Sort by offset (in reverse order).
- std::sort(Ops.begin(), Ops.end(),
- [](const MachineInstr *LHS, const MachineInstr *RHS) {
- int LOffset = getMemoryOpOffset(*LHS);
- int ROffset = getMemoryOpOffset(*RHS);
- assert(LHS == RHS || LOffset != ROffset);
- return LOffset > ROffset;
- });
+ llvm::sort(Ops.begin(), Ops.end(),
+ [](const MachineInstr *LHS, const MachineInstr *RHS) {
+ int LOffset = getMemoryOpOffset(*LHS);
+ int ROffset = getMemoryOpOffset(*RHS);
+ assert(LHS == RHS || LOffset != ROffset);
+ return LOffset > ROffset;
+ });
// The loads / stores of the same base are in order. Scan them from first to
// last and check for the following:
@@ -2253,7 +2253,7 @@ bool ARMPreAllocLoadStoreOpt::RescheduleOps(MachineBasicBlock *MBB,
// This is the new location for the loads / stores.
MachineBasicBlock::iterator InsertPos = isLd ? FirstOp : LastOp;
while (InsertPos != MBB->end() &&
- (MemOps.count(&*InsertPos) || InsertPos->isDebugValue()))
+ (MemOps.count(&*InsertPos) || InsertPos->isDebugInstr()))
++InsertPos;
// If we are moving a pair of loads / stores, see if it makes sense
@@ -2291,7 +2291,7 @@ bool ARMPreAllocLoadStoreOpt::RescheduleOps(MachineBasicBlock *MBB,
MIB.addReg(0);
MIB.addImm(Offset).addImm(Pred).addReg(PredReg);
MIB.setMemRefs(Op0->mergeMemRefsWith(*Op1));
- DEBUG(dbgs() << "Formed " << *MIB << "\n");
+ LLVM_DEBUG(dbgs() << "Formed " << *MIB << "\n");
++NumLDRDFormed;
} else {
MachineInstrBuilder MIB = BuildMI(*MBB, InsertPos, dl, MCID)
@@ -2305,7 +2305,7 @@ bool ARMPreAllocLoadStoreOpt::RescheduleOps(MachineBasicBlock *MBB,
MIB.addReg(0);
MIB.addImm(Offset).addImm(Pred).addReg(PredReg);
MIB.setMemRefs(Op0->mergeMemRefsWith(*Op1));
- DEBUG(dbgs() << "Formed " << *MIB << "\n");
+ LLVM_DEBUG(dbgs() << "Formed " << *MIB << "\n");
++NumSTRDFormed;
}
MBB->erase(Op0);
@@ -2355,7 +2355,7 @@ ARMPreAllocLoadStoreOpt::RescheduleLoadStoreInstrs(MachineBasicBlock *MBB) {
break;
}
- if (!MI.isDebugValue())
+ if (!MI.isDebugInstr())
MI2LocMap[&MI] = ++Loc;
if (!isMemoryOp(MI))
diff --git a/lib/Target/ARM/ARMMacroFusion.cpp b/lib/Target/ARM/ARMMacroFusion.cpp
index 5c9aad417ceb..d11fe9d5c502 100644
--- a/lib/Target/ARM/ARMMacroFusion.cpp
+++ b/lib/Target/ARM/ARMMacroFusion.cpp
@@ -19,7 +19,48 @@
namespace llvm {
-/// \brief Check if the instr pair, FirstMI and SecondMI, should be fused
+// Fuse AES crypto encoding or decoding.
+static bool isAESPair(const MachineInstr *FirstMI,
+ const MachineInstr &SecondMI) {
+ // Assume the 1st instr to be a wildcard if it is unspecified.
+ unsigned FirstOpcode =
+ FirstMI ? FirstMI->getOpcode()
+ : static_cast<unsigned>(ARM::INSTRUCTION_LIST_END);
+ unsigned SecondOpcode = SecondMI.getOpcode();
+
+ switch(SecondOpcode) {
+ // AES encode.
+ case ARM::AESMC :
+ return FirstOpcode == ARM::AESE ||
+ FirstOpcode == ARM::INSTRUCTION_LIST_END;
+ // AES decode.
+ case ARM::AESIMC:
+ return FirstOpcode == ARM::AESD ||
+ FirstOpcode == ARM::INSTRUCTION_LIST_END;
+ }
+
+ return false;
+}
+
+// Fuse literal generation.
+static bool isLiteralsPair(const MachineInstr *FirstMI,
+ const MachineInstr &SecondMI) {
+ // Assume the 1st instr to be a wildcard if it is unspecified.
+ unsigned FirstOpcode =
+ FirstMI ? FirstMI->getOpcode()
+ : static_cast<unsigned>(ARM::INSTRUCTION_LIST_END);
+ unsigned SecondOpcode = SecondMI.getOpcode();
+
+ // 32 bit immediate.
+ if ((FirstOpcode == ARM::INSTRUCTION_LIST_END ||
+ FirstOpcode == ARM::MOVi16) &&
+ SecondOpcode == ARM::MOVTi16)
+ return true;
+
+ return false;
+}
+
+/// Check if the instr pair, FirstMI and SecondMI, should be fused
/// together. Given SecondMI, when FirstMI is unspecified, then check if
/// SecondMI may be part of a fused pair at all.
static bool shouldScheduleAdjacent(const TargetInstrInfo &TII,
@@ -28,24 +69,10 @@ static bool shouldScheduleAdjacent(const TargetInstrInfo &TII,
const MachineInstr &SecondMI) {
const ARMSubtarget &ST = static_cast<const ARMSubtarget&>(TSI);
- // Assume wildcards for unspecified instrs.
- unsigned FirstOpcode =
- FirstMI ? FirstMI->getOpcode()
- : static_cast<unsigned>(ARM::INSTRUCTION_LIST_END);
- unsigned SecondOpcode = SecondMI.getOpcode();
-
- if (ST.hasFuseAES())
- // Fuse AES crypto operations.
- switch(SecondOpcode) {
- // AES encode.
- case ARM::AESMC :
- return FirstOpcode == ARM::AESE ||
- FirstOpcode == ARM::INSTRUCTION_LIST_END;
- // AES decode.
- case ARM::AESIMC:
- return FirstOpcode == ARM::AESD ||
- FirstOpcode == ARM::INSTRUCTION_LIST_END;
- }
+ if (ST.hasFuseAES() && isAESPair(FirstMI, SecondMI))
+ return true;
+ if (ST.hasFuseLiterals() && isLiteralsPair(FirstMI, SecondMI))
+ return true;
return false;
}
diff --git a/lib/Target/ARM/ARMParallelDSP.cpp b/lib/Target/ARM/ARMParallelDSP.cpp
new file mode 100644
index 000000000000..9d5478b76c18
--- /dev/null
+++ b/lib/Target/ARM/ARMParallelDSP.cpp
@@ -0,0 +1,672 @@
+//===- ParallelDSP.cpp - Parallel DSP Pass --------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file
+/// Armv6 introduced instructions to perform 32-bit SIMD operations. The
+/// purpose of this pass is do some IR pattern matching to create ACLE
+/// DSP intrinsics, which map on these 32-bit SIMD operations.
+/// This pass runs only when unaligned accesses is supported/enabled.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/Statistic.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/Analysis/AliasAnalysis.h"
+#include "llvm/Analysis/LoopAccessAnalysis.h"
+#include "llvm/Analysis/LoopPass.h"
+#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/NoFolder.h"
+#include "llvm/Transforms/Scalar.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+#include "llvm/Transforms/Utils/LoopUtils.h"
+#include "llvm/Pass.h"
+#include "llvm/PassRegistry.h"
+#include "llvm/PassSupport.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/IR/PatternMatch.h"
+#include "llvm/CodeGen/TargetPassConfig.h"
+#include "ARM.h"
+#include "ARMSubtarget.h"
+
+using namespace llvm;
+using namespace PatternMatch;
+
+#define DEBUG_TYPE "arm-parallel-dsp"
+
+STATISTIC(NumSMLAD , "Number of smlad instructions generated");
+
+namespace {
+ struct OpChain;
+ struct BinOpChain;
+ struct Reduction;
+
+ using OpChainList = SmallVector<std::unique_ptr<OpChain>, 8>;
+ using ReductionList = SmallVector<Reduction, 8>;
+ using ValueList = SmallVector<Value*, 8>;
+ using MemInstList = SmallVector<Instruction*, 8>;
+ using PMACPair = std::pair<BinOpChain*,BinOpChain*>;
+ using PMACPairList = SmallVector<PMACPair, 8>;
+ using Instructions = SmallVector<Instruction*,16>;
+ using MemLocList = SmallVector<MemoryLocation, 4>;
+
+ struct OpChain {
+ Instruction *Root;
+ ValueList AllValues;
+ MemInstList VecLd; // List of all load instructions.
+ MemLocList MemLocs; // All memory locations read by this tree.
+ bool ReadOnly = true;
+
+ OpChain(Instruction *I, ValueList &vl) : Root(I), AllValues(vl) { }
+ virtual ~OpChain() = default;
+
+ void SetMemoryLocations() {
+ const auto Size = MemoryLocation::UnknownSize;
+ for (auto *V : AllValues) {
+ if (auto *I = dyn_cast<Instruction>(V)) {
+ if (I->mayWriteToMemory())
+ ReadOnly = false;
+ if (auto *Ld = dyn_cast<LoadInst>(V))
+ MemLocs.push_back(MemoryLocation(Ld->getPointerOperand(), Size));
+ }
+ }
+ }
+
+ unsigned size() const { return AllValues.size(); }
+ };
+
+ // 'BinOpChain' and 'Reduction' are just some bookkeeping data structures.
+ // 'Reduction' contains the phi-node and accumulator statement from where we
+ // start pattern matching, and 'BinOpChain' the multiplication
+ // instructions that are candidates for parallel execution.
+ struct BinOpChain : public OpChain {
+ ValueList LHS; // List of all (narrow) left hand operands.
+ ValueList RHS; // List of all (narrow) right hand operands.
+
+ BinOpChain(Instruction *I, ValueList &lhs, ValueList &rhs) :
+ OpChain(I, lhs), LHS(lhs), RHS(rhs) {
+ for (auto *V : RHS)
+ AllValues.push_back(V);
+ }
+ };
+
+ struct Reduction {
+ PHINode *Phi; // The Phi-node from where we start
+ // pattern matching.
+ Instruction *AccIntAdd; // The accumulating integer add statement,
+ // i.e, the reduction statement.
+
+ OpChainList MACCandidates; // The MAC candidates associated with
+ // this reduction statement.
+ Reduction (PHINode *P, Instruction *Acc) : Phi(P), AccIntAdd(Acc) { };
+ };
+
+ class ARMParallelDSP : public LoopPass {
+ ScalarEvolution *SE;
+ AliasAnalysis *AA;
+ TargetLibraryInfo *TLI;
+ DominatorTree *DT;
+ LoopInfo *LI;
+ Loop *L;
+ const DataLayout *DL;
+ Module *M;
+
+ bool InsertParallelMACs(Reduction &Reduction, PMACPairList &PMACPairs);
+ bool AreSequentialLoads(LoadInst *Ld0, LoadInst *Ld1, MemInstList &VecMem);
+ PMACPairList CreateParallelMACPairs(OpChainList &Candidates);
+ Instruction *CreateSMLADCall(LoadInst *VecLd0, LoadInst *VecLd1,
+ Instruction *Acc, Instruction *InsertAfter);
+
+ /// Try to match and generate: SMLAD, SMLADX - Signed Multiply Accumulate
+ /// Dual performs two signed 16x16-bit multiplications. It adds the
+ /// products to a 32-bit accumulate operand. Optionally, the instruction can
+ /// exchange the halfwords of the second operand before performing the
+ /// arithmetic.
+ bool MatchSMLAD(Function &F);
+
+ public:
+ static char ID;
+
+ ARMParallelDSP() : LoopPass(ID) { }
+
+ void getAnalysisUsage(AnalysisUsage &AU) const override {
+ LoopPass::getAnalysisUsage(AU);
+ AU.addRequired<AssumptionCacheTracker>();
+ AU.addRequired<ScalarEvolutionWrapperPass>();
+ AU.addRequired<AAResultsWrapperPass>();
+ AU.addRequired<TargetLibraryInfoWrapperPass>();
+ AU.addRequired<LoopInfoWrapperPass>();
+ AU.addRequired<DominatorTreeWrapperPass>();
+ AU.addRequired<TargetPassConfig>();
+ AU.addPreserved<LoopInfoWrapperPass>();
+ AU.setPreservesCFG();
+ }
+
+ bool runOnLoop(Loop *TheLoop, LPPassManager &) override {
+ L = TheLoop;
+ SE = &getAnalysis<ScalarEvolutionWrapperPass>().getSE();
+ AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
+ TLI = &getAnalysis<TargetLibraryInfoWrapperPass>().getTLI();
+ DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
+ LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
+ auto &TPC = getAnalysis<TargetPassConfig>();
+
+ BasicBlock *Header = TheLoop->getHeader();
+ if (!Header)
+ return false;
+
+ // TODO: We assume the loop header and latch to be the same block.
+ // This is not a fundamental restriction, but lifting this would just
+ // require more work to do the transformation and then patch up the CFG.
+ if (Header != TheLoop->getLoopLatch()) {
+ LLVM_DEBUG(dbgs() << "The loop header is not the loop latch: not "
+ "running pass ARMParallelDSP\n");
+ return false;
+ }
+
+ Function &F = *Header->getParent();
+ M = F.getParent();
+ DL = &M->getDataLayout();
+
+ auto &TM = TPC.getTM<TargetMachine>();
+ auto *ST = &TM.getSubtarget<ARMSubtarget>(F);
+
+ if (!ST->allowsUnalignedMem()) {
+ LLVM_DEBUG(dbgs() << "Unaligned memory access not supported: not "
+ "running pass ARMParallelDSP\n");
+ return false;
+ }
+
+ if (!ST->hasDSP()) {
+ LLVM_DEBUG(dbgs() << "DSP extension not enabled: not running pass "
+ "ARMParallelDSP\n");
+ return false;
+ }
+
+ LoopAccessInfo LAI(L, SE, TLI, AA, DT, LI);
+ bool Changes = false;
+
+ LLVM_DEBUG(dbgs() << "\n== Parallel DSP pass ==\n\n");
+ Changes = MatchSMLAD(F);
+ return Changes;
+ }
+ };
+}
+
+// MaxBitwidth: the maximum supported bitwidth of the elements in the DSP
+// instructions, which is set to 16. So here we should collect all i8 and i16
+// narrow operations.
+// TODO: we currently only collect i16, and will support i8 later, so that's
+// why we check that types are equal to MaxBitWidth, and not <= MaxBitWidth.
+template<unsigned MaxBitWidth>
+static bool IsNarrowSequence(Value *V, ValueList &VL) {
+ LLVM_DEBUG(dbgs() << "Is narrow sequence? "; V->dump());
+ ConstantInt *CInt;
+
+ if (match(V, m_ConstantInt(CInt))) {
+ // TODO: if a constant is used, it needs to fit within the bit width.
+ return false;
+ }
+
+ auto *I = dyn_cast<Instruction>(V);
+ if (!I)
+ return false;
+
+ Value *Val, *LHS, *RHS;
+ if (match(V, m_Trunc(m_Value(Val)))) {
+ if (cast<TruncInst>(I)->getDestTy()->getIntegerBitWidth() == MaxBitWidth)
+ return IsNarrowSequence<MaxBitWidth>(Val, VL);
+ } else if (match(V, m_Add(m_Value(LHS), m_Value(RHS)))) {
+ // TODO: we need to implement sadd16/sadd8 for this, which enables to
+ // also do the rewrite for smlad8.ll, but it is unsupported for now.
+ LLVM_DEBUG(dbgs() << "No, unsupported Op:\t"; I->dump());
+ return false;
+ } else if (match(V, m_ZExtOrSExt(m_Value(Val)))) {
+ if (cast<CastInst>(I)->getSrcTy()->getIntegerBitWidth() != MaxBitWidth) {
+ LLVM_DEBUG(dbgs() << "No, wrong SrcTy size: " <<
+ cast<CastInst>(I)->getSrcTy()->getIntegerBitWidth() << "\n");
+ return false;
+ }
+
+ if (match(Val, m_Load(m_Value()))) {
+ LLVM_DEBUG(dbgs() << "Yes, found narrow Load:\t"; Val->dump());
+ VL.push_back(Val);
+ VL.push_back(I);
+ return true;
+ }
+ }
+ LLVM_DEBUG(dbgs() << "No, unsupported Op:\t"; I->dump());
+ return false;
+}
+
+// Element-by-element comparison of Value lists returning true if they are
+// instructions with the same opcode or constants with the same value.
+static bool AreSymmetrical(const ValueList &VL0,
+ const ValueList &VL1) {
+ if (VL0.size() != VL1.size()) {
+ LLVM_DEBUG(dbgs() << "Muls are mismatching operand list lengths: "
+ << VL0.size() << " != " << VL1.size() << "\n");
+ return false;
+ }
+
+ const unsigned Pairs = VL0.size();
+ LLVM_DEBUG(dbgs() << "Number of operand pairs: " << Pairs << "\n");
+
+ for (unsigned i = 0; i < Pairs; ++i) {
+ const Value *V0 = VL0[i];
+ const Value *V1 = VL1[i];
+ const auto *Inst0 = dyn_cast<Instruction>(V0);
+ const auto *Inst1 = dyn_cast<Instruction>(V1);
+
+ LLVM_DEBUG(dbgs() << "Pair " << i << ":\n";
+ dbgs() << "mul1: "; V0->dump();
+ dbgs() << "mul2: "; V1->dump());
+
+ if (!Inst0 || !Inst1)
+ return false;
+
+ if (Inst0->isSameOperationAs(Inst1)) {
+ LLVM_DEBUG(dbgs() << "OK: same operation found!\n");
+ continue;
+ }
+
+ const APInt *C0, *C1;
+ if (!(match(V0, m_APInt(C0)) && match(V1, m_APInt(C1)) && C0 == C1))
+ return false;
+ }
+
+ LLVM_DEBUG(dbgs() << "OK: found symmetrical operand lists.\n");
+ return true;
+}
+
+template<typename MemInst>
+static bool AreSequentialAccesses(MemInst *MemOp0, MemInst *MemOp1,
+ MemInstList &VecMem, const DataLayout &DL,
+ ScalarEvolution &SE) {
+ if (!MemOp0->isSimple() || !MemOp1->isSimple()) {
+ LLVM_DEBUG(dbgs() << "No, not touching volatile access\n");
+ return false;
+ }
+ if (isConsecutiveAccess(MemOp0, MemOp1, DL, SE)) {
+ VecMem.push_back(MemOp0);
+ VecMem.push_back(MemOp1);
+ LLVM_DEBUG(dbgs() << "OK: accesses are consecutive.\n");
+ return true;
+ }
+ LLVM_DEBUG(dbgs() << "No, accesses aren't consecutive.\n");
+ return false;
+}
+
+bool ARMParallelDSP::AreSequentialLoads(LoadInst *Ld0, LoadInst *Ld1,
+ MemInstList &VecMem) {
+ if (!Ld0 || !Ld1)
+ return false;
+
+ LLVM_DEBUG(dbgs() << "Are consecutive loads:\n";
+ dbgs() << "Ld0:"; Ld0->dump();
+ dbgs() << "Ld1:"; Ld1->dump();
+ );
+
+ if (!Ld0->hasOneUse() || !Ld1->hasOneUse()) {
+ LLVM_DEBUG(dbgs() << "No, load has more than one use.\n");
+ return false;
+ }
+
+ return AreSequentialAccesses<LoadInst>(Ld0, Ld1, VecMem, *DL, *SE);
+}
+
+PMACPairList
+ARMParallelDSP::CreateParallelMACPairs(OpChainList &Candidates) {
+ const unsigned Elems = Candidates.size();
+ PMACPairList PMACPairs;
+
+ if (Elems < 2)
+ return PMACPairs;
+
+ // TODO: for now we simply try to match consecutive pairs i and i+1.
+ // We can compare all elements, but then we need to compare and evaluate
+ // different solutions.
+ for(unsigned i=0; i<Elems-1; i+=2) {
+ BinOpChain *PMul0 = static_cast<BinOpChain*>(Candidates[i].get());
+ BinOpChain *PMul1 = static_cast<BinOpChain*>(Candidates[i+1].get());
+ const Instruction *Mul0 = PMul0->Root;
+ const Instruction *Mul1 = PMul1->Root;
+
+ if (Mul0 == Mul1)
+ continue;
+
+ LLVM_DEBUG(dbgs() << "\nCheck parallel muls:\n";
+ dbgs() << "- "; Mul0->dump();
+ dbgs() << "- "; Mul1->dump());
+
+ const ValueList &Mul0_LHS = PMul0->LHS;
+ const ValueList &Mul0_RHS = PMul0->RHS;
+ const ValueList &Mul1_LHS = PMul1->LHS;
+ const ValueList &Mul1_RHS = PMul1->RHS;
+
+ if (!AreSymmetrical(Mul0_LHS, Mul1_LHS) ||
+ !AreSymmetrical(Mul0_RHS, Mul1_RHS))
+ continue;
+
+ LLVM_DEBUG(dbgs() << "OK: mul operands list match:\n");
+ // The first elements of each vector should be loads with sexts. If we find
+ // that its two pairs of consecutive loads, then these can be transformed
+ // into two wider loads and the users can be replaced with DSP
+ // intrinsics.
+ for (unsigned x = 0; x < Mul0_LHS.size(); x += 2) {
+ auto *Ld0 = dyn_cast<LoadInst>(Mul0_LHS[x]);
+ auto *Ld1 = dyn_cast<LoadInst>(Mul1_LHS[x]);
+ auto *Ld2 = dyn_cast<LoadInst>(Mul0_RHS[x]);
+ auto *Ld3 = dyn_cast<LoadInst>(Mul1_RHS[x]);
+
+ LLVM_DEBUG(dbgs() << "Looking at operands " << x << ":\n";
+ dbgs() << "\t mul1: "; Mul0_LHS[x]->dump();
+ dbgs() << "\t mul2: "; Mul1_LHS[x]->dump();
+ dbgs() << "and operands " << x + 2 << ":\n";
+ dbgs() << "\t mul1: "; Mul0_RHS[x]->dump();
+ dbgs() << "\t mul2: "; Mul1_RHS[x]->dump());
+
+ if (AreSequentialLoads(Ld0, Ld1, PMul0->VecLd) &&
+ AreSequentialLoads(Ld2, Ld3, PMul1->VecLd)) {
+ LLVM_DEBUG(dbgs() << "OK: found two pairs of parallel loads!\n");
+ PMACPairs.push_back(std::make_pair(PMul0, PMul1));
+ }
+ }
+ }
+ return PMACPairs;
+}
+
+bool ARMParallelDSP::InsertParallelMACs(Reduction &Reduction,
+ PMACPairList &PMACPairs) {
+ Instruction *Acc = Reduction.Phi;
+ Instruction *InsertAfter = Reduction.AccIntAdd;
+
+ for (auto &Pair : PMACPairs) {
+ LLVM_DEBUG(dbgs() << "Found parallel MACs!!\n";
+ dbgs() << "- "; Pair.first->Root->dump();
+ dbgs() << "- "; Pair.second->Root->dump());
+ auto *VecLd0 = cast<LoadInst>(Pair.first->VecLd[0]);
+ auto *VecLd1 = cast<LoadInst>(Pair.second->VecLd[0]);
+ Acc = CreateSMLADCall(VecLd0, VecLd1, Acc, InsertAfter);
+ InsertAfter = Acc;
+ }
+
+ if (Acc != Reduction.Phi) {
+ LLVM_DEBUG(dbgs() << "Replace Accumulate: "; Acc->dump());
+ Reduction.AccIntAdd->replaceAllUsesWith(Acc);
+ return true;
+ }
+ return false;
+}
+
+static void MatchReductions(Function &F, Loop *TheLoop, BasicBlock *Header,
+ ReductionList &Reductions) {
+ RecurrenceDescriptor RecDesc;
+ const bool HasFnNoNaNAttr =
+ F.getFnAttribute("no-nans-fp-math").getValueAsString() == "true";
+ const BasicBlock *Latch = TheLoop->getLoopLatch();
+
+ // We need a preheader as getIncomingValueForBlock assumes there is one.
+ if (!TheLoop->getLoopPreheader()) {
+ LLVM_DEBUG(dbgs() << "No preheader found, bailing out\n");
+ return;
+ }
+
+ for (PHINode &Phi : Header->phis()) {
+ const auto *Ty = Phi.getType();
+ if (!Ty->isIntegerTy(32))
+ continue;
+
+ const bool IsReduction =
+ RecurrenceDescriptor::AddReductionVar(&Phi,
+ RecurrenceDescriptor::RK_IntegerAdd,
+ TheLoop, HasFnNoNaNAttr, RecDesc);
+ if (!IsReduction)
+ continue;
+
+ Instruction *Acc = dyn_cast<Instruction>(Phi.getIncomingValueForBlock(Latch));
+ if (!Acc)
+ continue;
+
+ Reductions.push_back(Reduction(&Phi, Acc));
+ }
+
+ LLVM_DEBUG(
+ dbgs() << "\nAccumulating integer additions (reductions) found:\n";
+ for (auto &R : Reductions) {
+ dbgs() << "- "; R.Phi->dump();
+ dbgs() << "-> "; R.AccIntAdd->dump();
+ }
+ );
+}
+
+static void AddMACCandidate(OpChainList &Candidates,
+ const Instruction *Acc,
+ Value *MulOp0, Value *MulOp1, int MulOpNum) {
+ Instruction *Mul = dyn_cast<Instruction>(Acc->getOperand(MulOpNum));
+ LLVM_DEBUG(dbgs() << "OK, found acc mul:\t"; Mul->dump());
+ ValueList LHS;
+ ValueList RHS;
+ if (IsNarrowSequence<16>(MulOp0, LHS) &&
+ IsNarrowSequence<16>(MulOp1, RHS)) {
+ LLVM_DEBUG(dbgs() << "OK, found narrow mul: "; Mul->dump());
+ Candidates.push_back(make_unique<BinOpChain>(Mul, LHS, RHS));
+ }
+}
+
+static void MatchParallelMACSequences(Reduction &R,
+ OpChainList &Candidates) {
+ const Instruction *Acc = R.AccIntAdd;
+ Value *A, *MulOp0, *MulOp1;
+ LLVM_DEBUG(dbgs() << "\n- Analysing:\t"; Acc->dump());
+
+ // Pattern 1: the accumulator is the RHS of the mul.
+ while(match(Acc, m_Add(m_Mul(m_Value(MulOp0), m_Value(MulOp1)),
+ m_Value(A)))){
+ AddMACCandidate(Candidates, Acc, MulOp0, MulOp1, 0);
+ Acc = dyn_cast<Instruction>(A);
+ }
+ // Pattern 2: the accumulator is the LHS of the mul.
+ while(match(Acc, m_Add(m_Value(A),
+ m_Mul(m_Value(MulOp0), m_Value(MulOp1))))) {
+ AddMACCandidate(Candidates, Acc, MulOp0, MulOp1, 1);
+ Acc = dyn_cast<Instruction>(A);
+ }
+
+ // The last mul in the chain has a slightly different pattern:
+ // the mul is the first operand
+ if (match(Acc, m_Add(m_Mul(m_Value(MulOp0), m_Value(MulOp1)), m_Value(A))))
+ AddMACCandidate(Candidates, Acc, MulOp0, MulOp1, 0);
+
+ // Because we start at the bottom of the chain, and we work our way up,
+ // the muls are added in reverse program order to the list.
+ std::reverse(Candidates.begin(), Candidates.end());
+}
+
+// Collects all instructions that are not part of the MAC chains, which is the
+// set of instructions that can potentially alias with the MAC operands.
+static void AliasCandidates(BasicBlock *Header, Instructions &Reads,
+ Instructions &Writes) {
+ for (auto &I : *Header) {
+ if (I.mayReadFromMemory())
+ Reads.push_back(&I);
+ if (I.mayWriteToMemory())
+ Writes.push_back(&I);
+ }
+}
+
+// Check whether statements in the basic block that write to memory alias with
+// the memory locations accessed by the MAC-chains.
+// TODO: we need the read statements when we accept more complicated chains.
+static bool AreAliased(AliasAnalysis *AA, Instructions &Reads,
+ Instructions &Writes, OpChainList &MACCandidates) {
+ LLVM_DEBUG(dbgs() << "Alias checks:\n");
+ for (auto &MAC : MACCandidates) {
+ LLVM_DEBUG(dbgs() << "mul: "; MAC->Root->dump());
+
+ // At the moment, we allow only simple chains that only consist of reads,
+ // accumulate their result with an integer add, and thus that don't write
+ // memory, and simply bail if they do.
+ if (!MAC->ReadOnly)
+ return true;
+
+ // Now for all writes in the basic block, check that they don't alias with
+ // the memory locations accessed by our MAC-chain:
+ for (auto *I : Writes) {
+ LLVM_DEBUG(dbgs() << "- "; I->dump());
+ assert(MAC->MemLocs.size() >= 2 && "expecting at least 2 memlocs");
+ for (auto &MemLoc : MAC->MemLocs) {
+ if (isModOrRefSet(intersectModRef(AA->getModRefInfo(I, MemLoc),
+ ModRefInfo::ModRef))) {
+ LLVM_DEBUG(dbgs() << "Yes, aliases found\n");
+ return true;
+ }
+ }
+ }
+ }
+
+ LLVM_DEBUG(dbgs() << "OK: no aliases found!\n");
+ return false;
+}
+
+static bool CheckMACMemory(OpChainList &Candidates) {
+ for (auto &C : Candidates) {
+ // A mul has 2 operands, and a narrow op consist of sext and a load; thus
+ // we expect at least 4 items in this operand value list.
+ if (C->size() < 4) {
+ LLVM_DEBUG(dbgs() << "Operand list too short.\n");
+ return false;
+ }
+ C->SetMemoryLocations();
+ ValueList &LHS = static_cast<BinOpChain*>(C.get())->LHS;
+ ValueList &RHS = static_cast<BinOpChain*>(C.get())->RHS;
+
+ // Use +=2 to skip over the expected extend instructions.
+ for (unsigned i = 0, e = LHS.size(); i < e; i += 2) {
+ if (!isa<LoadInst>(LHS[i]) || !isa<LoadInst>(RHS[i]))
+ return false;
+ }
+ }
+ return true;
+}
+
+// Loop Pass that needs to identify integer add/sub reductions of 16-bit vector
+// multiplications.
+// To use SMLAD:
+// 1) we first need to find integer add reduction PHIs,
+// 2) then from the PHI, look for this pattern:
+//
+// acc0 = phi i32 [0, %entry], [%acc1, %loop.body]
+// ld0 = load i16
+// sext0 = sext i16 %ld0 to i32
+// ld1 = load i16
+// sext1 = sext i16 %ld1 to i32
+// mul0 = mul %sext0, %sext1
+// ld2 = load i16
+// sext2 = sext i16 %ld2 to i32
+// ld3 = load i16
+// sext3 = sext i16 %ld3 to i32
+// mul1 = mul i32 %sext2, %sext3
+// add0 = add i32 %mul0, %acc0
+// acc1 = add i32 %add0, %mul1
+//
+// Which can be selected to:
+//
+// ldr.h r0
+// ldr.h r1
+// smlad r2, r0, r1, r2
+//
+// If constants are used instead of loads, these will need to be hoisted
+// out and into a register.
+//
+// If loop invariants are used instead of loads, these need to be packed
+// before the loop begins.
+//
+bool ARMParallelDSP::MatchSMLAD(Function &F) {
+ BasicBlock *Header = L->getHeader();
+ LLVM_DEBUG(dbgs() << "= Matching SMLAD =\n";
+ dbgs() << "Header block:\n"; Header->dump();
+ dbgs() << "Loop info:\n\n"; L->dump());
+
+ bool Changed = false;
+ ReductionList Reductions;
+ MatchReductions(F, L, Header, Reductions);
+
+ for (auto &R : Reductions) {
+ OpChainList MACCandidates;
+ MatchParallelMACSequences(R, MACCandidates);
+ if (!CheckMACMemory(MACCandidates))
+ continue;
+
+ R.MACCandidates = std::move(MACCandidates);
+
+ LLVM_DEBUG(dbgs() << "MAC candidates:\n";
+ for (auto &M : R.MACCandidates)
+ M->Root->dump();
+ dbgs() << "\n";);
+ }
+
+ // Collect all instructions that may read or write memory. Our alias
+ // analysis checks bail out if any of these instructions aliases with an
+ // instruction from the MAC-chain.
+ Instructions Reads, Writes;
+ AliasCandidates(Header, Reads, Writes);
+
+ for (auto &R : Reductions) {
+ if (AreAliased(AA, Reads, Writes, R.MACCandidates))
+ return false;
+ PMACPairList PMACPairs = CreateParallelMACPairs(R.MACCandidates);
+ Changed |= InsertParallelMACs(R, PMACPairs);
+ }
+
+ LLVM_DEBUG(if (Changed) dbgs() << "Header block:\n"; Header->dump(););
+ return Changed;
+}
+
+static void CreateLoadIns(IRBuilder<NoFolder> &IRB, Instruction *Acc,
+ LoadInst **VecLd) {
+ const Type *AccTy = Acc->getType();
+ const unsigned AddrSpace = (*VecLd)->getPointerAddressSpace();
+
+ Value *VecPtr = IRB.CreateBitCast((*VecLd)->getPointerOperand(),
+ AccTy->getPointerTo(AddrSpace));
+ *VecLd = IRB.CreateAlignedLoad(VecPtr, (*VecLd)->getAlignment());
+}
+
+Instruction *ARMParallelDSP::CreateSMLADCall(LoadInst *VecLd0, LoadInst *VecLd1,
+ Instruction *Acc,
+ Instruction *InsertAfter) {
+ LLVM_DEBUG(dbgs() << "Create SMLAD intrinsic using:\n";
+ dbgs() << "- "; VecLd0->dump();
+ dbgs() << "- "; VecLd1->dump();
+ dbgs() << "- "; Acc->dump());
+
+ IRBuilder<NoFolder> Builder(InsertAfter->getParent(),
+ ++BasicBlock::iterator(InsertAfter));
+
+ // Replace the reduction chain with an intrinsic call
+ CreateLoadIns(Builder, Acc, &VecLd0);
+ CreateLoadIns(Builder, Acc, &VecLd1);
+ Value* Args[] = { VecLd0, VecLd1, Acc };
+ Function *SMLAD = Intrinsic::getDeclaration(M, Intrinsic::arm_smlad);
+ CallInst *Call = Builder.CreateCall(SMLAD, Args);
+ NumSMLAD++;
+ return Call;
+}
+
+Pass *llvm::createARMParallelDSPPass() {
+ return new ARMParallelDSP();
+}
+
+char ARMParallelDSP::ID = 0;
+
+INITIALIZE_PASS_BEGIN(ARMParallelDSP, "arm-parallel-dsp",
+ "Transform loops to use DSP intrinsics", false, false)
+INITIALIZE_PASS_END(ARMParallelDSP, "arm-parallel-dsp",
+ "Transform loops to use DSP intrinsics", false, false)
diff --git a/lib/Target/ARM/ARMRegisterBankInfo.cpp b/lib/Target/ARM/ARMRegisterBankInfo.cpp
index fad0e98285e6..0e16d6bcfe2b 100644
--- a/lib/Target/ARM/ARMRegisterBankInfo.cpp
+++ b/lib/Target/ARM/ARMRegisterBankInfo.cpp
@@ -175,15 +175,20 @@ const RegisterBank &ARMRegisterBankInfo::getRegBankFromRegClass(
switch (RC.getID()) {
case GPRRegClassID:
+ case GPRwithAPSRRegClassID:
case GPRnopcRegClassID:
+ case rGPRRegClassID:
case GPRspRegClassID:
case tGPR_and_tcGPRRegClassID:
+ case tcGPRRegClassID:
case tGPRRegClassID:
return getRegBank(ARM::GPRRegBankID);
+ case HPRRegClassID:
case SPR_8RegClassID:
case SPRRegClassID:
case DPR_8RegClassID:
case DPRRegClassID:
+ case QPRRegClassID:
return getRegBank(ARM::FPRRegBankID);
default:
llvm_unreachable("Unsupported register kind");
@@ -263,13 +268,74 @@ ARMRegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
case G_FADD:
case G_FSUB:
case G_FMUL:
- case G_FDIV: {
+ case G_FDIV:
+ case G_FNEG: {
LLT Ty = MRI.getType(MI.getOperand(0).getReg());
OperandsMapping =Ty.getSizeInBits() == 64
? &ARM::ValueMappings[ARM::DPR3OpsIdx]
: &ARM::ValueMappings[ARM::SPR3OpsIdx];
break;
}
+ case G_FMA: {
+ LLT Ty = MRI.getType(MI.getOperand(0).getReg());
+ OperandsMapping =
+ Ty.getSizeInBits() == 64
+ ? getOperandsMapping({&ARM::ValueMappings[ARM::DPR3OpsIdx],
+ &ARM::ValueMappings[ARM::DPR3OpsIdx],
+ &ARM::ValueMappings[ARM::DPR3OpsIdx],
+ &ARM::ValueMappings[ARM::DPR3OpsIdx]})
+ : getOperandsMapping({&ARM::ValueMappings[ARM::SPR3OpsIdx],
+ &ARM::ValueMappings[ARM::SPR3OpsIdx],
+ &ARM::ValueMappings[ARM::SPR3OpsIdx],
+ &ARM::ValueMappings[ARM::SPR3OpsIdx]});
+ break;
+ }
+ case G_FPEXT: {
+ LLT ToTy = MRI.getType(MI.getOperand(0).getReg());
+ LLT FromTy = MRI.getType(MI.getOperand(1).getReg());
+ if (ToTy.getSizeInBits() == 64 && FromTy.getSizeInBits() == 32)
+ OperandsMapping =
+ getOperandsMapping({&ARM::ValueMappings[ARM::DPR3OpsIdx],
+ &ARM::ValueMappings[ARM::SPR3OpsIdx]});
+ break;
+ }
+ case G_FPTRUNC: {
+ LLT ToTy = MRI.getType(MI.getOperand(0).getReg());
+ LLT FromTy = MRI.getType(MI.getOperand(1).getReg());
+ if (ToTy.getSizeInBits() == 32 && FromTy.getSizeInBits() == 64)
+ OperandsMapping =
+ getOperandsMapping({&ARM::ValueMappings[ARM::SPR3OpsIdx],
+ &ARM::ValueMappings[ARM::DPR3OpsIdx]});
+ break;
+ }
+ case G_FPTOSI:
+ case G_FPTOUI: {
+ LLT ToTy = MRI.getType(MI.getOperand(0).getReg());
+ LLT FromTy = MRI.getType(MI.getOperand(1).getReg());
+ if ((FromTy.getSizeInBits() == 32 || FromTy.getSizeInBits() == 64) &&
+ ToTy.getSizeInBits() == 32)
+ OperandsMapping =
+ FromTy.getSizeInBits() == 64
+ ? getOperandsMapping({&ARM::ValueMappings[ARM::GPR3OpsIdx],
+ &ARM::ValueMappings[ARM::DPR3OpsIdx]})
+ : getOperandsMapping({&ARM::ValueMappings[ARM::GPR3OpsIdx],
+ &ARM::ValueMappings[ARM::SPR3OpsIdx]});
+ break;
+ }
+ case G_SITOFP:
+ case G_UITOFP: {
+ LLT ToTy = MRI.getType(MI.getOperand(0).getReg());
+ LLT FromTy = MRI.getType(MI.getOperand(1).getReg());
+ if (FromTy.getSizeInBits() == 32 &&
+ (ToTy.getSizeInBits() == 32 || ToTy.getSizeInBits() == 64))
+ OperandsMapping =
+ ToTy.getSizeInBits() == 64
+ ? getOperandsMapping({&ARM::ValueMappings[ARM::DPR3OpsIdx],
+ &ARM::ValueMappings[ARM::GPR3OpsIdx]})
+ : getOperandsMapping({&ARM::ValueMappings[ARM::SPR3OpsIdx],
+ &ARM::ValueMappings[ARM::GPR3OpsIdx]});
+ break;
+ }
case G_CONSTANT:
case G_FRAME_INDEX:
case G_GLOBAL_VALUE:
diff --git a/lib/Target/ARM/ARMRegisterBanks.td b/lib/Target/ARM/ARMRegisterBanks.td
index 7cd2d60d36a4..6e3834da3bb5 100644
--- a/lib/Target/ARM/ARMRegisterBanks.td
+++ b/lib/Target/ARM/ARMRegisterBanks.td
@@ -11,4 +11,4 @@
//===----------------------------------------------------------------------===//
def GPRRegBank : RegisterBank<"GPRB", [GPR, GPRwithAPSR]>;
-def FPRRegBank : RegisterBank<"FPRB", [SPR, DPR]>;
+def FPRRegBank : RegisterBank<"FPRB", [HPR, SPR, DPR, QPR]>;
diff --git a/lib/Target/ARM/ARMRegisterInfo.td b/lib/Target/ARM/ARMRegisterInfo.td
index 14526b777c70..dc56186cb54a 100644
--- a/lib/Target/ARM/ARMRegisterInfo.td
+++ b/lib/Target/ARM/ARMRegisterInfo.td
@@ -307,6 +307,18 @@ def SPR : RegisterClass<"ARM", [f32], 32, (sequence "S%u", 0, 31)> {
let DiagnosticString = "operand must be a register in range [s0, s31]";
}
+def HPR : RegisterClass<"ARM", [f16], 32, (sequence "S%u", 0, 31)> {
+ let AltOrders = [(add (decimate HPR, 2), SPR),
+ (add (decimate HPR, 4),
+ (decimate HPR, 2),
+ (decimate (rotl HPR, 1), 4),
+ (decimate (rotl HPR, 1), 2))];
+ let AltOrderSelect = [{
+ return 1 + MF.getSubtarget<ARMSubtarget>().useStride4VFPs(MF);
+ }];
+ let DiagnosticString = "operand must be a register in range [s0, s31]";
+}
+
// Subset of SPR which can be used as a source of NEON scalars for 16-bit
// operations
def SPR_8 : RegisterClass<"ARM", [f32], 32, (sequence "S%u", 0, 15)> {
diff --git a/lib/Target/ARM/ARMScheduleA57.td b/lib/Target/ARM/ARMScheduleA57.td
index 1ed9e14dfcd6..63f975ba6e39 100644
--- a/lib/Target/ARM/ARMScheduleA57.td
+++ b/lib/Target/ARM/ARMScheduleA57.td
@@ -92,6 +92,9 @@ def CortexA57Model : SchedMachineModel {
// Enable partial & runtime unrolling.
let LoopMicroOpBufferSize = 16;
let CompleteModel = 1;
+
+ // FIXME: Remove when all errors have been fixed.
+ let FullInstRWOverlapCheck = 0;
}
//===----------------------------------------------------------------------===//
@@ -125,8 +128,9 @@ def : InstRW<[WriteNoop], (instregex "(t)?BKPT$", "(t2)?CDP(2)?$",
"(t2)?CPS[123]p$", "(t2)?DBG$", "(t2)?DMB$", "(t2)?DSB$", "ERET$",
"(t2|t)?HINT$", "(t)?HLT$", "(t2)?HVC$", "(t2)?ISB$", "ITasm$",
"(t2)?RFE(DA|DB|IA|IB)", "(t)?SETEND", "(t2)?SETPAN", "(t2)?SMC", "SPACE",
- "(t2)?SRS(DA|DB|IA|IB)", "SWP(B)?", "t?TRAP", "UDF$", "t2DCPS", "t2SG",
- "t2TT", "tCPS", "CMP_SWAP", "t?SVC", "t2IT", "CompilerBarrier")>;
+ "(t2)?SRS(DA|DB|IA|IB)", "SWP(B)?", "t?TRAP", "(t2|t)?UDF$", "t2DCPS", "t2SG",
+ "t2TT", "tCPS", "CMP_SWAP", "t?SVC", "t2IT", "CompilerBarrier",
+ "t__brkdiv0")>;
def : InstRW<[WriteNoop], (instregex "VMRS", "VMSR", "FMSTAT")>;
@@ -146,7 +150,7 @@ def : InstRW<[WriteNoop], (instregex "FLDM", "FSTM")>;
// Pseudos
def : InstRW<[WriteNoop], (instregex "(t2)?ABS$",
"(t)?ADJCALLSTACKDOWN$", "(t)?ADJCALLSTACKUP$", "(t2|t)?Int_eh_sjlj",
- "tLDRpci_pic", "t2SUBS_PC_LR",
+ "tLDRpci_pic", "(t2)?SUBS_PC_LR",
"JUMPTABLE", "tInt_WIN_eh_sjlj_longjmp",
"VLD(1|2)LN(d|q)(WB_fixed_|WB_register_)?Asm",
"VLD(3|4)(DUP|LN)?(d|q)(WB_fixed_|WB_register_)?Asm",
@@ -279,6 +283,9 @@ def A57WriteMLA : SchedWriteRes<[A57UnitM]> { let Latency = 3; }
def A57WriteMLAL : SchedWriteRes<[A57UnitM]> { let Latency = 4; }
def A57ReadMLA : SchedReadAdvance<2, [A57WriteMLA, A57WriteMLAL]>;
+def : InstRW<[A57WriteMLA],
+ (instregex "t2SMLAD", "t2SMLADX", "t2SMLSD", "t2SMLSDX")>;
+
def : SchedAlias<WriteMAC16, A57WriteMLA>;
def : SchedAlias<WriteMAC32, A57WriteMLA>;
def : SchedAlias<ReadMAC, A57ReadMLA>;
@@ -587,6 +594,8 @@ def : InstRW<[A57WriteLDM], (instregex "(t|t2|sys)?LDM(IA|DA|DB|IB)$")>;
def : InstRW<[A57WriteLDM_Upd],
(instregex "(t|t2|sys)?LDM(IA_UPD|DA_UPD|DB_UPD|IB_UPD|IA_RET)", "tPOP")>;
+def : InstRW<[A57Write_5cyc_1L], (instregex "VLLDM")>;
+
// --- 3.9 Store Instructions ---
// Store, immed offset
@@ -705,6 +714,8 @@ def : InstRW<[A57WriteSTM], (instregex "(t2|sys|t)?STM(IA|DA|DB|IB)$")>;
def : InstRW<[A57WrBackOne, A57WriteSTM_Upd],
(instregex "(t2|sys|t)?STM(IA_UPD|DA_UPD|DB_UPD|IB_UPD)", "tPUSH")>;
+def : InstRW<[A57Write_5cyc_1S], (instregex "VLSTM")>;
+
// --- 3.10 FP Data Processing Instructions ---
def : SchedAlias<WriteFPALU32, A57Write_5cyc_1V>;
def : SchedAlias<WriteFPALU64, A57Write_5cyc_1V>;
@@ -722,9 +733,11 @@ def : InstRW<[A57WriteVcmp],
// fp convert
def : InstRW<[A57Write_5cyc_1V], (instregex
"VCVT(A|N|P|M)(SH|UH|SS|US|SD|UD)", "VCVT(BDH|THD|TDH)")>;
-
+def : InstRW<[A57Write_5cyc_1V], (instregex "VTOSLS", "VTOUHS", "VTOULS")>;
def : SchedAlias<WriteFPCVT, A57Write_5cyc_1V>;
+def : InstRW<[A57Write_5cyc_1V], (instregex "VJCVT")>;
+
// FP round to integral
def : InstRW<[A57Write_5cyc_1V], (instregex "VRINT(A|N|P|M|Z|R|X)(H|S|D)$")>;
@@ -734,6 +747,8 @@ def : SchedAlias<WriteFPDIV64, A57Write_32cyc_1W>;
def : SchedAlias<WriteFPSQRT32, A57Write_17cyc_1W>;
def : SchedAlias<WriteFPSQRT64, A57Write_32cyc_1W>;
+def : InstRW<[A57Write_17cyc_1W], (instregex "VSQRTH")>;
+
// FP max/min
def : InstRW<[A57Write_5cyc_1V], (instregex "VMAX", "VMIN")>;
@@ -767,6 +782,13 @@ def : SchedAlias<WriteFPMAC32, A57WriteVFMA>;
def : SchedAlias<WriteFPMAC64, A57WriteVFMA>;
def : SchedAlias<ReadFPMAC, A57ReadVFMA5>;
+// VMLAH/VMLSH are not binded to scheduling classes by default, so here custom:
+def : InstRW<[A57WriteVFMA, A57ReadVFMA5, ReadFPMUL, ReadFPMUL],
+ (instregex "VMLAH", "VMLSH", "VNMLAH", "VNMLSH")>;
+
+def : InstRW<[A57WriteVMUL],
+ (instregex "VUDOTD", "VSDOTD", "VUDOTQ", "VSDOTQ")>;
+
def : InstRW<[A57Write_3cyc_1V], (instregex "VNEG")>;
def : InstRW<[A57Write_3cyc_1V], (instregex "VSEL")>;
@@ -775,6 +797,8 @@ def : InstRW<[A57Write_3cyc_1V], (instregex "VSEL")>;
def : InstRW<[A57Write_3cyc_1V], (instregex "FCONST(D|S|H)")>;
def : InstRW<[A57Write_3cyc_1V], (instregex "VMOV(D|S|H)(cc)?$")>;
+def : InstRW<[A57Write_3cyc_1V], (instregex "VINSH")>;
+
// 5cyc L for FP transfer, vfp to core reg,
// 5cyc L for FP transfer, core reg to vfp
def : SchedAlias<WriteFPMOV, A57Write_5cyc_1L>;
@@ -1062,6 +1086,11 @@ def A57ReadVQDMLAL_VecInt : SchedReadVariant<[
def : InstRW<[A57WriteVQDMLAL_VecInt, A57ReadVQDMLAL_VecInt],
(instregex "VQDMLAL", "VQDMLSL")>;
+// Vector Saturating Rounding Doubling Multiply Accumulate/Subtract Long
+// Scheduling info from VQDMLAL/VQDMLSL
+def : InstRW<[A57WriteVQDMLAL_VecInt, A57ReadVQDMLAL_VecInt],
+ (instregex "VQRDMLAH", "VQRDMLSH")>;
+
// ASIMD multiply long
// 5cyc F0 for r0px, 4cyc F0 for r1p0 and later
def A57WriteVMULL_VecInt : SchedWriteVariant<[
@@ -1126,6 +1155,8 @@ def : InstRW<[A57Write_3cyc_1V], (instregex "VABS(fd|fq|hd|hq)")>;
def : InstRW<[A57Write_5cyc_1V], (instregex "VABD(fd|fq|hd|hq)",
"VADD(fd|fq|hd|hq)", "VPADD(f|h)", "VSUB(fd|fq|hd|hq)")>;
+def : InstRW<[A57Write_5cyc_1V], (instregex "VCADD", "VCMLA")>;
+
// ASIMD FP compare
def : InstRW<[A57Write_5cyc_1V], (instregex "VAC(GE|GT|LE|LT)",
"VC(EQ|GE|GT|LE)(fd|fq|hd|hq)")>;
@@ -1184,7 +1215,7 @@ def : InstRW<[A57Write_3cyc_1V], (instregex "VEXT(d|q)(8|16|32|64)")>;
// ASIMD move, immed
def : InstRW<[A57Write_3cyc_1V], (instregex
"VMOV(v8i8|v16i8|v4i16|v8i16|v2i32|v4i32|v1i64|v2i64|v2f32|v4f32)",
- "VMOVQ0")>;
+ "VMOVD0", "VMOVQ0")>;
// ASIMD move, narrowing
def : InstRW<[A57Write_3cyc_1V], (instregex "VMOVN")>;
diff --git a/lib/Target/ARM/ARMScheduleA9.td b/lib/Target/ARM/ARMScheduleA9.td
index 4e72b13d94cb..fc301c589269 100644
--- a/lib/Target/ARM/ARMScheduleA9.td
+++ b/lib/Target/ARM/ARMScheduleA9.td
@@ -1898,6 +1898,9 @@ def CortexA9Model : SchedMachineModel {
// FIXME: Many vector operations were never given an itinerary. We
// haven't mapped these to the new model either.
let CompleteModel = 0;
+
+ // FIXME: Remove when all errors have been fixed.
+ let FullInstRWOverlapCheck = 0;
}
//===----------------------------------------------------------------------===//
@@ -1993,15 +1996,15 @@ def : WriteRes<WriteVST4, []>;
// Reserve A9UnitFP for 2 consecutive cycles.
def A9Write2V4 : SchedWriteRes<[A9UnitFP, A9UnitAGU]> {
let Latency = 4;
- let ResourceCycles = [2];
+ let ResourceCycles = [2, 1];
}
def A9Write2V7 : SchedWriteRes<[A9UnitFP, A9UnitAGU]> {
let Latency = 7;
- let ResourceCycles = [2];
+ let ResourceCycles = [2, 1];
}
def A9Write2V9 : SchedWriteRes<[A9UnitFP, A9UnitAGU]> {
let Latency = 9;
- let ResourceCycles = [2];
+ let ResourceCycles = [2, 1];
}
// Branches don't have a def operand but still consume resources.
@@ -2534,8 +2537,7 @@ def : SchedAlias<WriteCMPsr, A9WriteALU>;
def : InstRW< [A9WriteIsr], (instregex "MOVsr", "MOVsi", "MVNsr", "MOVCCsi",
"MOVCCsr")>;
def : InstRW< [WriteALU, A9ReadALU], (instregex "MVNr")>;
-def : InstRW< [A9WriteI2], (instregex "MOVCCi32imm", "MOVi32imm",
- "MOV_ga_dyn")>;
+def : InstRW< [A9WriteI2], (instregex "MOVCCi32imm", "MOVi32imm")>;
def : InstRW< [A9WriteI2pc], (instregex "MOV_ga_pcrel")>;
def : InstRW< [A9WriteI2ld], (instregex "MOV_ga_pcrel_ldr")>;
@@ -2548,12 +2550,12 @@ def : InstRW< [A9WriteM],
"SMMLA", "SMMLAR", "SMMLS", "SMMLSR")>;
def : InstRW< [A9WriteM, A9WriteMHi],
(instregex "SMULL", "SMULLv5", "UMULL", "UMULLv5", "SMLAL$", "UMLAL",
- "UMAAL", "SMLALv5", "UMLALv5", "UMAALv5", "SMLALBB", "SMLALBT", "SMLALTB",
+ "UMAAL", "SMLALv5", "UMLALv5", "SMLALBB", "SMLALBT", "SMLALTB",
"SMLALTT")>;
// FIXME: These instructions used to have NoItinerary. Just copied the one from above.
def : InstRW< [A9WriteM, A9WriteMHi],
(instregex "SMLAD", "SMLADX", "SMLALD", "SMLALDX", "SMLSD", "SMLSDX",
- "SMLSLD", "SMLLDX", "SMUAD", "SMUADX", "SMUSD", "SMUSDX")>;
+ "SMLSLD", "SMLSLDX", "SMUAD", "SMUADX", "SMUSD", "SMUSDX")>;
def : InstRW<[A9WriteM16, A9WriteM16Hi],
(instregex "SMULBB", "SMULBT", "SMULTB", "SMULTT", "SMULWB", "SMULWT")>;
diff --git a/lib/Target/ARM/ARMScheduleR52.td b/lib/Target/ARM/ARMScheduleR52.td
index ca3172808d36..11bce45161b3 100644
--- a/lib/Target/ARM/ARMScheduleR52.td
+++ b/lib/Target/ARM/ARMScheduleR52.td
@@ -217,12 +217,11 @@ def : InstRW<[R52WriteALU_EX2, R52Read_EX1, R52Read_ISS],
"t2SXTB", "t2SXTH", "t2SXTB16", "t2UXTB", "t2UXTH", "t2UXTB16")>;
def : InstRW<[R52WriteALU_EX1, R52Read_ISS],
- (instregex "MOVCCi32imm", "MOVi32imm", "MOV_ga_dyn", "t2MOVCCi",
- "t2MOVi", "t2MOV_ga_dyn")>;
+ (instregex "MOVCCi32imm", "MOVi32imm", "t2MOVCCi", "t2MOVi")>;
def : InstRW<[R52WriteALU_EX2, R52Read_EX1],
- (instregex "MOV_ga_pcrel", "t2MOV_ga_pcrel")>;
+ (instregex "MOV_ga_pcrel$")>;
def : InstRW<[R52WriteLd,R52Read_ISS],
- (instregex "MOV_ga_pcrel_ldr", "t2MOV_ga_pcrel_ldr")>;
+ (instregex "MOV_ga_pcrel_ldr")>;
def : InstRW<[R52WriteALU_EX2, R52Read_EX1, R52Read_EX1], (instregex "SEL", "t2SEL")>;
@@ -257,12 +256,12 @@ def : InstRW< [R52WriteALU_EX2, R52Read_EX1, R52Read_EX1],
// Sum of Absolute Difference
def : InstRW< [R52WriteALU_WRI, R52Read_ISS, R52Read_ISS, R52Read_ISS],
- (instregex "USAD8", "t2USAD8", "tUSAD8","USADA8", "t2USADA8", "tUSADA8") >;
+ (instregex "USAD8", "t2USAD8", "USADA8", "t2USADA8") >;
// Integer Multiply
def : InstRW<[R52WriteMAC, R52Read_ISS, R52Read_ISS],
- (instregex "MULS", "MUL", "SMMUL", "SMMULR", "SMULBB", "SMULBT",
- "SMULTB", "SMULTT", "SMULWB", "SMULWT", "SMUSD", "SMUSDXi", "t2MUL",
+ (instregex "MUL", "SMMUL", "SMMULR", "SMULBB", "SMULBT",
+ "SMULTB", "SMULTT", "SMULWB", "SMULWT", "SMUSD", "SMUSDX", "t2MUL",
"t2SMMUL", "t2SMMULR", "t2SMULBB", "t2SMULBT", "t2SMULTB", "t2SMULTT",
"t2SMULWB", "t2SMULWT", "t2SMUSD")>;
@@ -270,17 +269,17 @@ def : InstRW<[R52WriteMAC, R52Read_ISS, R52Read_ISS],
// Even for 64-bit accumulation (or Long), the single MAC is used (not ALUs).
// The store pipeline is used partly for 64-bit operations.
def : InstRW<[R52WriteMAC, R52Read_ISS, R52Read_ISS, R52Read_ISS],
- (instregex "MLAS", "MLA", "MLS", "SMMLA", "SMMLAR", "SMMLS", "SMMLSR",
- "t2MLA", "t2MLS", "t2MLAS", "t2SMMLA", "t2SMMLAR", "t2SMMLS", "t2SMMLSR",
+ (instregex "MLA", "MLS", "SMMLA", "SMMLAR", "SMMLS", "SMMLSR",
+ "t2MLA", "t2MLS", "t2SMMLA", "t2SMMLAR", "t2SMMLS", "t2SMMLSR",
"SMUAD", "SMUADX", "t2SMUAD", "t2SMUADX",
"SMLABB", "SMLABT", "SMLATB", "SMLATT", "SMLSD", "SMLSDX",
"SMLAWB", "SMLAWT", "t2SMLABB", "t2SMLABT", "t2SMLATB", "t2SMLATT",
"t2SMLSD", "t2SMLSDX", "t2SMLAWB", "t2SMLAWT",
"SMLAD", "SMLADX", "t2SMLAD", "t2SMLADX",
"SMULL$", "UMULL$", "t2SMULL$", "t2UMULL$",
- "SMLALS", "UMLALS", "SMLAL", "UMLAL", "MLALBB", "SMLALBT",
+ "SMLAL", "UMLAL", "SMLALBT",
"SMLALTB", "SMLALTT", "SMLALD", "SMLALDX", "SMLSLD", "SMLSLDX",
- "UMAAL", "t2SMLALS", "t2UMLALS", "t2SMLAL", "t2UMLAL", "t2MLALBB",
+ "UMAAL", "t2SMLAL", "t2UMLAL",
"t2SMLALBT", "t2SMLALTB", "t2SMLALTT", "t2SMLALD", "t2SMLALDX",
"t2SMLSLD", "t2SMLSLDX", "t2UMAAL")>;
@@ -301,31 +300,31 @@ def : InstRW<[R52WriteLd, R52WriteAdr, R52Read_ISS, R52Read_ISS],
"LDRBT_POST$", "LDR(T|BT)_POST_(REG|IMM)", "LDRHT(i|r)",
"t2LD(R|RB|RH)_(PRE|POST)", "t2LD(R|RB|RH)T",
"LDR(SH|SB)(_POST|_PRE)", "t2LDR(SH|SB)(_POST|_PRE)",
- "LDRS(B|H)T(i|r)", "t2LDRS(B|H)T(i|r)", "t2LDRS(B|H)T",
+ "LDRS(B|H)T(i|r)", "t2LDRS(B|H)T(i|r)?",
"LDRD_(POST|PRE)", "t2LDRD_(POST|PRE)")>;
def : InstRW<[R52WriteALU_EX2, R52Read_EX1], (instregex "MOVS?sr", "t2MOVS?sr")>;
def : InstRW<[R52WriteALU_WRI, R52Read_EX2], (instregex "MOVT", "t2MOVT")>;
-def : InstRW<[R52WriteALU_EX2, R52Read_EX1], (instregex "AD(C|D)S?ri","ANDS?ri",
+def : InstRW<[R52WriteALU_EX2, R52Read_EX1], (instregex "AD(C|D)S?ri", "ANDS?ri",
"BICS?ri", "CLZ", "EORri", "MVNS?r", "ORRri", "RSBS?ri", "RSCri", "SBCri",
"t2AD(C|D)S?ri", "t2ANDS?ri", "t2BICS?ri","t2CLZ", "t2EORri", "t2MVN",
"t2ORRri", "t2RSBS?ri", "t2SBCri")>;
def : InstRW<[R52WriteALU_EX2, R52Read_EX1, R52Read_EX1], (instregex "AD(C|D)S?rr",
- "ANDS?rr", "BICS?rr", "CRC*", "EORrr", "ORRrr", "RSBrr", "RSCrr", "SBCrr",
+ "ANDS?rr", "BICS?rr", "CRC", "EORrr", "ORRrr", "RSBrr", "RSCrr", "SBCrr",
"t2AD(C|D)S?rr", "t2ANDS?rr", "t2BICS?rr", "t2CRC", "t2EORrr", "t2SBCrr")>;
def : InstRW<[R52WriteALU_EX2, R52Read_EX1, R52Read_ISS], (instregex "AD(C|D)S?rsi",
"ANDS?rsi", "BICS?rsi", "EORrsi", "ORRrsi", "RSBrsi", "RSCrsi", "SBCrsi",
- "t2AD(|D)S?rsi", "t2ANDS?rsi", "t2BICS?rsi", "t2EORrsi", "t2ORRrsi", "t2RSBrsi", "t2SBCrsi")>;
+ "t2AD(C|D)S?rs", "t2ANDS?rs", "t2BICS?rs", "t2EORrs", "t2ORRrs", "t2RSBrs", "t2SBCrs")>;
def : InstRW<[R52WriteALU_EX2, R52Read_EX1, R52Read_ISS, R52Read_ISS],
(instregex "AD(C|D)S?rsr", "ANDS?rsr", "BICS?rsr", "EORrsr", "MVNS?sr",
- "ORRrsrr", "RSBrsr", "RSCrsr", "SBCrsr")>;
+ "ORRrsr", "RSBrsr", "RSCrsr", "SBCrsr")>;
def : InstRW<[R52WriteALU_EX1],
- (instregex "ADR", "MOVSi", "MOVSsi", "MOVST?i16*", "MVNS?s?i", "t2MOVS?si")>;
+ (instregex "ADR", "MOVsi", "MVNS?s?i", "t2MOVS?si")>;
def : InstRW<[R52WriteALU_EX1, R52Read_ISS], (instregex "ASRi", "RORS?i")>;
def : InstRW<[R52WriteALU_EX1, R52Read_ISS, R52Read_ISS],
@@ -484,7 +483,7 @@ def : InstRW<[R52WriteILDM, R52Read_ISS],
def : InstRW<[R52WriteILDM, R52WriteAdr, R52Read_ISS],
(instregex "LDM(IA|DA|DB|IB)_UPD", "(t2|sys|t)LDM(IA|DA|DB|IB)_UPD")>;
def : InstRW<[R52WriteILDM, R52WriteAdr, R52Read_ISS],
- (instregex "LDMIA_RET", "(t|t2)LDMIA_RET", "POP", "tPOP")>;
+ (instregex "LDMIA_RET", "(t|t2)LDMIA_RET", "tPOP")>;
// Integer Store, Single Element
def : InstRW<[R52WriteLd, R52Read_ISS, R52Read_EX2],
@@ -500,7 +499,7 @@ def : InstRW<[R52WriteLd, R52WriteAdr, R52Read_ISS, R52Read_EX2],
// Integer Store, Dual
def : InstRW<[R52WriteLd, R52Read_ISS, R52Read_EX2],
- (instregex "STRD$", "t2STRDi8", "STL", "t2STRD$", "t2STL")>;
+ (instregex "STRD$", "t2STRDi8", "STL", "t2STL")>;
def : InstRW<[R52WriteLd, R52WriteAdr, R52Read_ISS, R52Read_EX2],
(instregex "(t2|t)STRD_(POST|PRE)", "STRD_(POST|PRE)")>;
@@ -508,11 +507,11 @@ def : InstRW<[R52WriteISTM, R52Read_ISS, R52Read_EX2],
(instregex "STM(IB|IA|DB|DA)$", "(t2|sys|t)STM(IB|IA|DB|DA)$")>;
def : InstRW<[R52WriteISTM, R52WriteAdr, R52Read_ISS, R52Read_EX2],
(instregex "STM(IB|IA|DB|DA)_UPD", "(t2|sys|t)STM(IB|IA|DB|DA)_UPD",
- "PUSH", "tPUSH")>;
+ "tPUSH")>;
// LDRLIT pseudo instructions, they expand to LDR + PICADD
def : InstRW<[R52WriteLd],
- (instregex "t?LDRLIT_ga_abs", "t?LDRLIT_ga_pcrel")>;
+ (instregex "t?LDRLIT_ga_abs", "t?LDRLIT_ga_pcrel$")>;
// LDRLIT_ga_pcrel_ldr expands to LDR + PICLDR
def : InstRW<[R52WriteLd], (instregex "LDRLIT_ga_pcrel_ldr")>;
@@ -530,7 +529,7 @@ def : InstRW<[R52Write2FPALU_F5, R52Read_F1], (instregex "VABS(fq|hq)")>;
def : InstRW<[R52WriteFPALU_F3, R52Read_F1, R52Read_F1], (instregex "(VACGE|VACGT)(fd|hd)")>;
def : InstRW<[R52Write2FPALU_F3, R52Read_F1, R52Read_F1], (instregex "(VACGE|VACGT)(fq|hq)")>;
-def : InstRW<[R52WriteFPALU_F5, R52Read_F1, R52Read_F1], (instregex "(VADD|VSUB)(D|S|H|fd|hd)")>;
+def : InstRW<[R52WriteFPALU_F5, R52Read_F1, R52Read_F1], (instregex "(VADD|VSUB)(D|S|H|fd|hd)$")>;
def : InstRW<[R52Write2FPALU_F5, R52Read_F1, R52Read_F1], (instregex "(VADD|VSUB)(fq|hq)")>;
def : InstRW<[R52WriteFPLd_F4, R52Read_ISS, R52Read_F1], (instregex "VLDR")>;
@@ -792,8 +791,6 @@ def : InstRW<[R52Write2FPALU_F3, R52Read_F2], (instregex "VBICi(v8i16|v4i32)")>;
def : InstRW<[R52WriteFPALU_F3, R52Read_F1, R52Read_F2, R52Read_F2], (instregex "(VBIF|VBIT|VBSL)d")>;
def : InstRW<[R52Write2FPALU_F3, R52Read_F1, R52Read_F2, R52Read_F2], (instregex "(VBIF|VBIT|VBSL)q")>;
-def : InstRW<[R52Write2FPALU_F3, R52Read_F2], (instregex "VBICi(v8i16|v4i32)")>;
-
def : InstRW<[R52WriteFPALU_F3, R52Read_F1, R52Read_F1],
(instregex "(VCEQ|VCGE|VCGT|VCLE|VCLT|VCLZ|VCMP|VCMPE|VCNT)")>;
def : InstRW<[R52WriteFPALU_F5, R52Read_F1, R52Read_F1],
diff --git a/lib/Target/ARM/ARMScheduleSwift.td b/lib/Target/ARM/ARMScheduleSwift.td
index b838688c6f04..87984648139b 100644
--- a/lib/Target/ARM/ARMScheduleSwift.td
+++ b/lib/Target/ARM/ARMScheduleSwift.td
@@ -44,6 +44,9 @@ def SwiftModel : SchedMachineModel {
let LoadLatency = 3;
let MispredictPenalty = 14; // A branch direction mispredict.
let CompleteModel = 0; // FIXME: Remove if all instructions are covered.
+
+ // FIXME: Remove when all errors have been fixed.
+ let FullInstRWOverlapCheck = 0;
}
// Swift predicates.
@@ -161,12 +164,12 @@ let SchedModel = SwiftModel in {
"t2UXTB16")>;
// Pseudo instructions.
def : InstRW<[SwiftWriteP01OneCycle2x],
- (instregex "MOVCCi32imm", "MOVi32imm", "MOV_ga_dyn", "t2MOVCCi32imm",
- "t2MOVi32imm", "t2MOV_ga_dyn")>;
+ (instregex "MOVCCi32imm", "MOVi32imm", "t2MOVCCi32imm",
+ "t2MOVi32imm")>;
def : InstRW<[SwiftWriteP01OneCycle3x],
(instregex "MOV_ga_pcrel", "t2MOV_ga_pcrel", "t2MOVi16_ga_pcrel")>;
def : InstRW<[SwiftWriteP01OneCycle2x_load],
- (instregex "MOV_ga_pcrel_ldr", "t2MOV_ga_pcrel_ldr")>;
+ (instregex "MOV_ga_pcrel_ldr")>;
def SwiftWriteP0TwoCycleTwoUops : WriteSequence<[SwiftWriteP0OneCycle], 2>;
@@ -218,8 +221,8 @@ let SchedModel = SwiftModel in {
// 4.2.12 Integer Multiply (32-bit result)
// Two sources.
def : InstRW< [SwiftWriteP0FourCycle],
- (instregex "MULS", "MUL", "SMMUL", "SMMULR", "SMULBB", "SMULBT",
- "SMULTB", "SMULTT", "SMULWB", "SMULWT", "SMUSD", "SMUSDXi", "t2MUL",
+ (instregex "MUL", "SMMUL", "SMMULR", "SMULBB", "SMULBT",
+ "SMULTB", "SMULTT", "SMULWB", "SMULWT", "SMUSD", "SMUSDX", "t2MUL",
"t2SMMUL", "t2SMMULR", "t2SMULBB", "t2SMULBT", "t2SMULTB", "t2SMULTT",
"t2SMULWB", "t2SMULWT", "t2SMUSD")>;
@@ -241,8 +244,8 @@ let SchedModel = SwiftModel in {
// Multiply accumulate, three sources
def : InstRW< [SwiftPredP0P01FourFiveCycle, ReadALU, ReadALU,
SwiftReadAdvanceFourCyclesPred],
- (instregex "MLAS", "MLA", "MLS", "SMMLA", "SMMLAR", "SMMLS", "SMMLSR",
- "t2MLA", "t2MLS", "t2MLAS", "t2SMMLA", "t2SMMLAR", "t2SMMLS",
+ (instregex "MLA", "MLS", "SMMLA", "SMMLAR", "SMMLS", "SMMLSR",
+ "t2MLA", "t2MLS", "t2SMMLA", "t2SMMLAR", "t2SMMLS",
"t2SMMLSR")>;
// 4.2.13 Integer Multiply (32-bit result, Q flag)
@@ -302,9 +305,9 @@ let SchedModel = SwiftModel in {
// We are being a bit inaccurate here.
def : InstRW< [SwiftWrite5Cycle, Swift2P03P01FiveCycle, ReadALU, ReadALU,
SchedReadAdvance<4>, SchedReadAdvance<3>],
- (instregex "SMLALS", "UMLALS", "SMLAL", "UMLAL", "MLALBB", "SMLALBT",
+ (instregex "SMLAL", "UMLAL", "SMLALBT",
"SMLALTB", "SMLALTT", "SMLALD", "SMLALDX", "SMLSLD", "SMLSLDX",
- "UMAAL", "t2SMLALS", "t2UMLALS", "t2SMLAL", "t2UMLAL", "t2MLALBB", "t2SMLALBT",
+ "UMAAL", "t2SMLAL", "t2UMLAL", "t2SMLALBB", "t2SMLALBT",
"t2SMLALTB", "t2SMLALTT", "t2SMLALD", "t2SMLALDX", "t2SMLSLD", "t2SMLSLDX",
"t2UMAAL")>;
@@ -366,7 +369,7 @@ let SchedModel = SwiftModel in {
"t2LD(R|RB|RH)_(PRE|POST)", "t2LD(R|RB|RH)T")>;
def : InstRW<[SwiftWriteP2P01P01FourCycle, SwiftWrBackOne],
(instregex "LDR(SH|SB)(_POST|_PRE)", "t2LDR(SH|SB)(_POST|_PRE)",
- "LDRS(B|H)T(i|r)", "t2LDRS(B|H)T(i|r)", "t2LDRS(B|H)T")>;
+ "LDRS(B|H)T(i|r)", "t2LDRS(B|H)T(i|r)?")>;
// 4.2.21 Integer Dual Load
// Not accurate.
@@ -483,7 +486,7 @@ let SchedModel = SwiftModel in {
(instregex /*"t2LDMIA_RET", "tLDMIA_RET", "LDMIA_RET",*/
"LDM(IA|DA|DB|IB)_UPD", "(t2|sys|t)LDM(IA|DA|DB|IB)_UPD")>;
def : InstRW<[SwiftWriteLDMAddrWB, SwiftWriteLM, SwiftWriteP1TwoCycle],
- (instregex "LDMIA_RET", "(t|t2)LDMIA_RET", "POP", "tPOP")>;
+ (instregex "LDMIA_RET", "(t|t2)LDMIA_RET", "tPOP")>;
// 4.2.23 Integer Store, Single Element
def : InstRW<[SwiftWriteP2],
(instregex "PICSTR", "STR(i12|rs)", "STRB(i12|rs)", "STRH$", "STREX",
@@ -533,7 +536,7 @@ let SchedModel = SwiftModel in {
(instregex "STM(IB|IA|DB|DA)$", "(t2|sys|t)STM(IB|IA|DB|DA)$")>;
def : InstRW<[SwiftWriteP01OneCycle, SwiftWriteSTM],
(instregex "STM(IB|IA|DB|DA)_UPD", "(t2|sys|t)STM(IB|IA|DB|DA)_UPD",
- "PUSH", "tPUSH")>;
+ "tPUSH")>;
// LDRLIT pseudo instructions, they expand to LDR + PICADD
def : InstRW<[SwiftWriteP2ThreeCycle, WriteALU],
@@ -549,14 +552,14 @@ let SchedModel = SwiftModel in {
// 4.2.27 Not issued
def : WriteRes<WriteNoop, []> { let Latency = 0; let NumMicroOps = 0; }
- def : InstRW<[WriteNoop], (instregex "t2IT", "IT", "NOP")>;
+ def : InstRW<[WriteNoop], (instregex "t2IT", "IT")>;
// 4.2.28 Advanced SIMD, Integer, 2 cycle
def : InstRW<[SwiftWriteP0TwoCycle],
(instregex "VADDv", "VSUBv", "VNEG(s|f|v)", "VADDL", "VSUBL",
"VADDW", "VSUBW", "VHADD", "VHSUB", "VRHADD", "VPADDi",
"VPADDL", "VAND", "VBIC", "VEOR", "VORN", "VORR", "VTST",
- "VSHL", "VSHR(s|u)", "VSHLL", "VQSHL", "VQSHLU", "VBIF",
+ "VSHL", "VSHR(s|u)", "VSHLL", "VQSHL(s|u)", "VBIF",
"VBIT", "VBSL", "VSLI", "VSRI", "VCLS", "VCLZ", "VCNT")>;
def : InstRW<[SwiftWriteP1TwoCycle],
@@ -566,7 +569,7 @@ let SchedModel = SwiftModel in {
// 4.2.30 Advanced SIMD, Integer with Accumulate
def : InstRW<[SwiftWriteP0FourCycle],
(instregex "VABA", "VABAL", "VPADAL", "VRSRA", "VSRA", "VACGE", "VACGT",
- "VACLE", "VACLT", "VCEQ", "VCGE", "VCGT", "VCLE", "VCLT", "VRSHL",
+ "VCEQ", "VCGE", "VCGT", "VCLE", "VCLT", "VRSHL",
"VQRSHL", "VRSHR(u|s)", "VABS(f|v)", "VQABS", "VQNEG", "VQADD",
"VQSUB")>;
def : InstRW<[SwiftWriteP1FourCycle],
@@ -623,12 +626,12 @@ let SchedModel = SwiftModel in {
// 4.2.37 Advanced SIMD and VFP, Move
def : InstRW<[SwiftWriteP0TwoCycle],
(instregex "VMOVv", "VMOV(S|D)$", "VMOV(S|D)cc",
- "VMVNv", "VMVN(d|q)", "VMVN(S|D)cc",
+ "VMVNv", "VMVN(d|q)",
"FCONST(D|S)")>;
def : InstRW<[SwiftWriteP1TwoCycle], (instregex "VMOVN", "VMOVL")>;
def : InstRW<[WriteSequence<[SwiftWriteP0FourCycle, SwiftWriteP1TwoCycle]>],
(instregex "VQMOVN")>;
- def : InstRW<[SwiftWriteP1TwoCycle], (instregex "VDUPLN", "VDUPf")>;
+ def : InstRW<[SwiftWriteP1TwoCycle], (instregex "VDUPLN")>;
def : InstRW<[WriteSequence<[SwiftWriteP2FourCycle, SwiftWriteP1TwoCycle]>],
(instregex "VDUP(8|16|32)")>;
def : InstRW<[SwiftWriteP2ThreeCycle], (instregex "VMOVRS$")>;
diff --git a/lib/Target/ARM/ARMSubtarget.cpp b/lib/Target/ARM/ARMSubtarget.cpp
index 23027e92481f..f42cbbda1b71 100644
--- a/lib/Target/ARM/ARMSubtarget.cpp
+++ b/lib/Target/ARM/ARMSubtarget.cpp
@@ -302,6 +302,8 @@ void ARMSubtarget::initSubtargetFeatures(StringRef CPU, StringRef FS) {
}
}
+bool ARMSubtarget::isTargetHardFloat() const { return TM.isTargetHardFloat(); }
+
bool ARMSubtarget::isAPCS_ABI() const {
assert(TM.TargetABI != ARMBaseTargetMachine::ARM_ABI_UNKNOWN);
return TM.TargetABI == ARMBaseTargetMachine::ARM_ABI_APCS;
diff --git a/lib/Target/ARM/ARMSubtarget.h b/lib/Target/ARM/ARMSubtarget.h
index eedb675a3304..74aee9a8ed38 100644
--- a/lib/Target/ARM/ARMSubtarget.h
+++ b/lib/Target/ARM/ARMSubtarget.h
@@ -105,6 +105,7 @@ protected:
ARMv81a,
ARMv82a,
ARMv83a,
+ ARMv84a,
ARMv8a,
ARMv8mBaseline,
ARMv8mMainline,
@@ -151,6 +152,7 @@ protected:
bool HasV8_1aOps = false;
bool HasV8_2aOps = false;
bool HasV8_3aOps = false;
+ bool HasV8_4aOps = false;
bool HasV8MBaselineOps = false;
bool HasV8MMainlineOps = false;
@@ -198,6 +200,9 @@ protected:
/// register allocation.
bool DisablePostRAScheduler = false;
+ /// UseAA - True if using AA during codegen (DAGCombine, MISched, etc)
+ bool UseAA = false;
+
/// HasThumb2 - True if Thumb2 instructions are supported.
bool HasThumb2 = false;
@@ -296,6 +301,12 @@ protected:
/// Has8MSecExt - if true, processor supports ARMv8-M Security Extensions
bool Has8MSecExt = false;
+ /// HasSHA2 - if true, processor supports SHA1 and SHA256
+ bool HasSHA2 = false;
+
+ /// HasAES - if true, processor supports AES
+ bool HasAES = false;
+
/// HasCrypto - if true, processor supports Cryptography extensions
bool HasCrypto = false;
@@ -316,6 +327,10 @@ protected:
/// pairs faster.
bool HasFuseAES = false;
+ /// HasFuseLiterals - if true, processor executes back to back
+ /// bottom and top halves of literal generation faster.
+ bool HasFuseLiterals = false;
+
/// If true, if conversion may decide to leave some instructions unpredicated.
bool IsProfitableToUnpredicate = false;
@@ -341,9 +356,12 @@ protected:
/// If true, the AGU and NEON/FPU units are multiplexed.
bool HasMuxedUnits = false;
- /// If true, VMOVS will never be widened to VMOVD
+ /// If true, VMOVS will never be widened to VMOVD.
bool DontWidenVMOVS = false;
+ /// If true, splat a register between VFP and NEON instructions.
+ bool SplatVFPToNeon = false;
+
/// If true, run the MLx expansion pass.
bool ExpandMLx = false;
@@ -510,6 +528,7 @@ public:
bool hasV8_1aOps() const { return HasV8_1aOps; }
bool hasV8_2aOps() const { return HasV8_2aOps; }
bool hasV8_3aOps() const { return HasV8_3aOps; }
+ bool hasV8_4aOps() const { return HasV8_4aOps; }
bool hasV8MBaselineOps() const { return HasV8MBaselineOps; }
bool hasV8MMainlineOps() const { return HasV8MMainlineOps; }
@@ -535,6 +554,8 @@ public:
bool hasVFP4() const { return HasVFPv4; }
bool hasFPARMv8() const { return HasFPARMv8; }
bool hasNEON() const { return HasNEON; }
+ bool hasSHA2() const { return HasSHA2; }
+ bool hasAES() const { return HasAES; }
bool hasCrypto() const { return HasCrypto; }
bool hasDotProd() const { return HasDotProd; }
bool hasCRC() const { return HasCRC; }
@@ -577,6 +598,7 @@ public:
bool hasSlowLoadDSubregister() const { return SlowLoadDSubregister; }
bool hasMuxedUnits() const { return HasMuxedUnits; }
bool dontWidenVMOVS() const { return DontWidenVMOVS; }
+ bool useSplatVFPToNeon() const { return SplatVFPToNeon; }
bool useNEONForFPMovs() const { return UseNEONForFPMovs; }
bool checkVLDnAccessAlignment() const { return CheckVLDnAlign; }
bool nonpipelinedVFP() const { return NonpipelinedVFP; }
@@ -598,8 +620,9 @@ public:
bool hasFullFP16() const { return HasFullFP16; }
bool hasFuseAES() const { return HasFuseAES; }
- /// \brief Return true if the CPU supports any kind of instruction fusion.
- bool hasFusion() const { return hasFuseAES(); }
+ bool hasFuseLiterals() const { return HasFuseLiterals; }
+ /// Return true if the CPU supports any kind of instruction fusion.
+ bool hasFusion() const { return hasFuseAES() || hasFuseLiterals(); }
const Triple &getTargetTriple() const { return TargetTriple; }
@@ -652,13 +675,7 @@ public:
!isTargetDarwin() && !isTargetWindows();
}
- bool isTargetHardFloat() const {
- // FIXME: this is invalid for WindowsCE
- return TargetTriple.getEnvironment() == Triple::GNUEABIHF ||
- TargetTriple.getEnvironment() == Triple::MuslEABIHF ||
- TargetTriple.getEnvironment() == Triple::EABIHF ||
- isTargetWindows() || isAAPCS16_ABI();
- }
+ bool isTargetHardFloat() const;
bool isTargetAndroid() const { return TargetTriple.isAndroid(); }
@@ -723,6 +740,10 @@ public:
/// True for some subtargets at > -O0.
bool enablePostRAScheduler() const override;
+ /// Enable use of alias analysis during code generation (during MI
+ /// scheduling, DAGCombine, etc.).
+ bool useAA() const override { return UseAA; }
+
// enableAtomicExpand- True if we need to expand our atomics.
bool enableAtomicExpand() const override;
diff --git a/lib/Target/ARM/ARMTargetMachine.cpp b/lib/Target/ARM/ARMTargetMachine.cpp
index 0f6d1eddc985..519f789fc215 100644
--- a/lib/Target/ARM/ARMTargetMachine.cpp
+++ b/lib/Target/ARM/ARMTargetMachine.cpp
@@ -22,7 +22,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Analysis/TargetTransformInfo.h"
-#include "llvm/CodeGen/ExecutionDepsFix.h"
+#include "llvm/CodeGen/ExecutionDomainFix.h"
#include "llvm/CodeGen/GlobalISel/CallLowering.h"
#include "llvm/CodeGen/GlobalISel/IRTranslator.h"
#include "llvm/CodeGen/GlobalISel/InstructionSelect.h"
@@ -34,7 +34,6 @@
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineScheduler.h"
#include "llvm/CodeGen/Passes.h"
-#include "llvm/CodeGen/TargetLoweringObjectFile.h"
#include "llvm/CodeGen/TargetPassConfig.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/DataLayout.h"
@@ -45,6 +44,7 @@
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/TargetParser.h"
#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Target/TargetLoweringObjectFile.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Transforms/Scalar.h"
#include <cassert>
@@ -75,7 +75,7 @@ EnableGlobalMerge("arm-global-merge", cl::Hidden,
cl::desc("Enable the global merge pass"));
namespace llvm {
- void initializeARMExecutionDepsFixPass(PassRegistry&);
+ void initializeARMExecutionDomainFixPass(PassRegistry&);
}
extern "C" void LLVMInitializeARMTarget() {
@@ -89,8 +89,10 @@ extern "C" void LLVMInitializeARMTarget() {
initializeGlobalISel(Registry);
initializeARMLoadStoreOptPass(Registry);
initializeARMPreAllocLoadStoreOptPass(Registry);
+ initializeARMParallelDSPPass(Registry);
+ initializeARMCodeGenPreparePass(Registry);
initializeARMConstantIslandsPass(Registry);
- initializeARMExecutionDepsFixPass(Registry);
+ initializeARMExecutionDomainFixPass(Registry);
initializeARMExpandPseudoPass(Registry);
initializeThumb2SizeReducePass(Registry);
}
@@ -214,11 +216,7 @@ ARMBaseTargetMachine::ARMBaseTargetMachine(const Target &T, const Triple &TT,
// Default to triple-appropriate float ABI
if (Options.FloatABIType == FloatABI::Default) {
- if (TargetTriple.getEnvironment() == Triple::GNUEABIHF ||
- TargetTriple.getEnvironment() == Triple::MuslEABIHF ||
- TargetTriple.getEnvironment() == Triple::EABIHF ||
- TargetTriple.isOSWindows() ||
- TargetABI == ARMBaseTargetMachine::ARM_ABI_AAPCS16)
+ if (isTargetHardFloat())
this->Options.FloatABIType = FloatABI::Hard;
else
this->Options.FloatABIType = FloatABI::Soft;
@@ -238,6 +236,11 @@ ARMBaseTargetMachine::ARMBaseTargetMachine(const Target &T, const Triple &TT,
this->Options.EABIVersion = EABI::EABI5;
}
+ if (TT.isOSBinFormatMachO()) {
+ this->Options.TrapUnreachable = true;
+ this->Options.NoTrapAfterNoreturn = true;
+ }
+
initAsmInfo();
}
@@ -344,6 +347,7 @@ public:
}
void addIRPasses() override;
+ void addCodeGenPrepare() override;
bool addPreISel() override;
bool addInstSelector() override;
bool addIRTranslator() override;
@@ -355,20 +359,23 @@ public:
void addPreEmitPass() override;
};
-class ARMExecutionDepsFix : public ExecutionDepsFix {
+class ARMExecutionDomainFix : public ExecutionDomainFix {
public:
static char ID;
- ARMExecutionDepsFix() : ExecutionDepsFix(ID, ARM::DPRRegClass) {}
+ ARMExecutionDomainFix() : ExecutionDomainFix(ID, ARM::DPRRegClass) {}
StringRef getPassName() const override {
- return "ARM Execution Dependency Fix";
+ return "ARM Execution Domain Fix";
}
};
-char ARMExecutionDepsFix::ID;
+char ARMExecutionDomainFix::ID;
} // end anonymous namespace
-INITIALIZE_PASS(ARMExecutionDepsFix, "arm-execution-deps-fix",
- "ARM Execution Dependency Fix", false, false)
+INITIALIZE_PASS_BEGIN(ARMExecutionDomainFix, "arm-execution-domain-fix",
+ "ARM Execution Domain Fix", false, false)
+INITIALIZE_PASS_DEPENDENCY(ReachingDefAnalysis)
+INITIALIZE_PASS_END(ARMExecutionDomainFix, "arm-execution-domain-fix",
+ "ARM Execution Domain Fix", false, false)
TargetPassConfig *ARMBaseTargetMachine::createPassConfig(PassManagerBase &PM) {
return new ARMPassConfig(*this, PM);
@@ -397,7 +404,16 @@ void ARMPassConfig::addIRPasses() {
addPass(createInterleavedAccessPass());
}
+void ARMPassConfig::addCodeGenPrepare() {
+ if (getOptLevel() != CodeGenOpt::None)
+ addPass(createARMCodeGenPreparePass());
+ TargetPassConfig::addCodeGenPrepare();
+}
+
bool ARMPassConfig::addPreISel() {
+ if (getOptLevel() != CodeGenOpt::None)
+ addPass(createARMParallelDSPPass());
+
if ((TM->getOptLevel() != CodeGenOpt::None &&
EnableGlobalMerge == cl::BOU_UNSET) ||
EnableGlobalMerge == cl::BOU_TRUE) {
@@ -462,7 +478,8 @@ void ARMPassConfig::addPreSched2() {
if (EnableARMLoadStoreOpt)
addPass(createARMLoadStoreOptimizationPass());
- addPass(new ARMExecutionDepsFix());
+ addPass(new ARMExecutionDomainFix());
+ addPass(createBreakFalseDeps());
}
// Expand some pseudo instructions into multiple instructions to allow
diff --git a/lib/Target/ARM/ARMTargetMachine.h b/lib/Target/ARM/ARMTargetMachine.h
index 2072bb731f0a..2c791998e702 100644
--- a/lib/Target/ARM/ARMTargetMachine.h
+++ b/lib/Target/ARM/ARMTargetMachine.h
@@ -61,6 +61,16 @@ public:
TargetLoweringObjectFile *getObjFileLowering() const override {
return TLOF.get();
}
+
+ bool isTargetHardFloat() const {
+ return TargetTriple.getEnvironment() == Triple::GNUEABIHF ||
+ TargetTriple.getEnvironment() == Triple::MuslEABIHF ||
+ TargetTriple.getEnvironment() == Triple::EABIHF ||
+ (TargetTriple.isOSBinFormatMachO() &&
+ TargetTriple.getSubArch() == Triple::ARMSubArch_v7em) ||
+ TargetTriple.isOSWindows() ||
+ TargetABI == ARMBaseTargetMachine::ARM_ABI_AAPCS16;
+ }
};
/// ARM/Thumb little endian target machine.
diff --git a/lib/Target/ARM/ARMTargetObjectFile.cpp b/lib/Target/ARM/ARMTargetObjectFile.cpp
index 88bab64ffaf2..d0620761ea9c 100644
--- a/lib/Target/ARM/ARMTargetObjectFile.cpp
+++ b/lib/Target/ARM/ARMTargetObjectFile.cpp
@@ -40,9 +40,6 @@ void ARMElfTargetObjectFile::Initialize(MCContext &Ctx,
if (isAAPCS_ABI) {
LSDASection = nullptr;
}
-
- AttributesSection =
- getContext().getELFSection(".ARM.attributes", ELF::SHT_ARM_ATTRIBUTES, 0);
}
const MCExpr *ARMElfTargetObjectFile::getTTypeGlobalReference(
diff --git a/lib/Target/ARM/ARMTargetObjectFile.h b/lib/Target/ARM/ARMTargetObjectFile.h
index bd7aa1cfe02b..0dc0882809c0 100644
--- a/lib/Target/ARM/ARMTargetObjectFile.h
+++ b/lib/Target/ARM/ARMTargetObjectFile.h
@@ -16,9 +16,6 @@
namespace llvm {
class ARMElfTargetObjectFile : public TargetLoweringObjectFileELF {
-protected:
- const MCSection *AttributesSection = nullptr;
-
public:
ARMElfTargetObjectFile()
: TargetLoweringObjectFileELF() {
@@ -33,7 +30,7 @@ public:
MachineModuleInfo *MMI,
MCStreamer &Streamer) const override;
- /// \brief Describe a TLS variable address within debug info.
+ /// Describe a TLS variable address within debug info.
const MCExpr *getDebugThreadLocalSymbol(const MCSymbol *Sym) const override;
MCSection *getExplicitSectionGlobal(const GlobalObject *GO, SectionKind Kind,
diff --git a/lib/Target/ARM/ARMTargetTransformInfo.cpp b/lib/Target/ARM/ARMTargetTransformInfo.cpp
index 43d7888075b5..f8cae31641ff 100644
--- a/lib/Target/ARM/ARMTargetTransformInfo.cpp
+++ b/lib/Target/ARM/ARMTargetTransformInfo.cpp
@@ -15,7 +15,6 @@
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/CodeGen/CostTable.h"
#include "llvm/CodeGen/ISDOpcodes.h"
-#include "llvm/CodeGen/MachineValueType.h"
#include "llvm/CodeGen/ValueTypes.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/CallSite.h"
@@ -26,6 +25,7 @@
#include "llvm/IR/Type.h"
#include "llvm/MC/SubtargetFeature.h"
#include "llvm/Support/Casting.h"
+#include "llvm/Support/MachineValueType.h"
#include "llvm/Target/TargetMachine.h"
#include <algorithm>
#include <cassert>
@@ -126,6 +126,10 @@ int ARMTTIImpl::getIntImmCost(unsigned Opcode, unsigned Idx, const APInt &Imm,
return 0;
}
+ // xor a, -1 can always be folded to MVN
+ if (Opcode == Instruction::Xor && Imm.isAllOnesValue())
+ return 0;
+
return getIntImmCost(Imm, Ty);
}
@@ -351,7 +355,7 @@ int ARMTTIImpl::getVectorInstrCost(unsigned Opcode, Type *ValTy,
int ARMTTIImpl::getCmpSelInstrCost(unsigned Opcode, Type *ValTy, Type *CondTy,
const Instruction *I) {
int ISD = TLI->InstructionOpcodeToISD(Opcode);
- // On NEON a a vector select gets lowered to vbsl.
+ // On NEON a vector select gets lowered to vbsl.
if (ST->hasNEON() && ValTy->isVectorTy() && ISD == ISD::SELECT) {
// Lowering of some vector selects is currently far from perfect.
static const TypeConversionCostTblEntry NEONVectorSelectTbl[] = {
@@ -396,8 +400,8 @@ int ARMTTIImpl::getAddressComputationCost(Type *Ty, ScalarEvolution *SE,
int ARMTTIImpl::getShuffleCost(TTI::ShuffleKind Kind, Type *Tp, int Index,
Type *SubTp) {
- // We only handle costs of reverse and alternate shuffles for now.
- if (Kind != TTI::SK_Reverse && Kind != TTI::SK_Alternate)
+ // We only handle costs of reverse and select shuffles for now.
+ if (Kind != TTI::SK_Reverse && Kind != TTI::SK_Select)
return BaseT::getShuffleCost(Kind, Tp, Index, SubTp);
if (Kind == TTI::SK_Reverse) {
@@ -422,9 +426,9 @@ int ARMTTIImpl::getShuffleCost(TTI::ShuffleKind Kind, Type *Tp, int Index,
return BaseT::getShuffleCost(Kind, Tp, Index, SubTp);
}
- if (Kind == TTI::SK_Alternate) {
- static const CostTblEntry NEONAltShuffleTbl[] = {
- // Alt shuffle cost table for ARM. Cost is the number of instructions
+ if (Kind == TTI::SK_Select) {
+ static const CostTblEntry NEONSelShuffleTbl[] = {
+ // Select shuffle cost table for ARM. Cost is the number of instructions
// required to create the shuffled vector.
{ISD::VECTOR_SHUFFLE, MVT::v2f32, 1},
@@ -441,7 +445,7 @@ int ARMTTIImpl::getShuffleCost(TTI::ShuffleKind Kind, Type *Tp, int Index,
{ISD::VECTOR_SHUFFLE, MVT::v16i8, 32}};
std::pair<int, MVT> LT = TLI->getTypeLegalizationCost(DL, Tp);
- if (const auto *Entry = CostTableLookup(NEONAltShuffleTbl,
+ if (const auto *Entry = CostTableLookup(NEONSelShuffleTbl,
ISD::VECTOR_SHUFFLE, LT.second))
return LT.first * Entry->Cost;
return BaseT::getShuffleCost(Kind, Tp, Index, SubTp);
@@ -579,9 +583,9 @@ void ARMTTIImpl::getUnrollingPreferences(Loop *L, ScalarEvolution &SE,
SmallVector<BasicBlock*, 4> ExitingBlocks;
L->getExitingBlocks(ExitingBlocks);
- DEBUG(dbgs() << "Loop has:\n"
- << "Blocks: " << L->getNumBlocks() << "\n"
- << "Exit blocks: " << ExitingBlocks.size() << "\n");
+ LLVM_DEBUG(dbgs() << "Loop has:\n"
+ << "Blocks: " << L->getNumBlocks() << "\n"
+ << "Exit blocks: " << ExitingBlocks.size() << "\n");
// Only allow another exit other than the latch. This acts as an early exit
// as it mirrors the profitability calculation of the runtime unroller.
@@ -612,12 +616,14 @@ void ARMTTIImpl::getUnrollingPreferences(Loop *L, ScalarEvolution &SE,
}
}
- DEBUG(dbgs() << "Cost of loop: " << Cost << "\n");
+ LLVM_DEBUG(dbgs() << "Cost of loop: " << Cost << "\n");
UP.Partial = true;
UP.Runtime = true;
UP.UnrollRemainder = true;
UP.DefaultUnrollRuntimeCount = 4;
+ UP.UnrollAndJam = true;
+ UP.UnrollAndJamInnerLoopThreshold = 60;
// Force unrolling small loops can be very useful because of the branch
// taken cost of the backedge.
diff --git a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
index 97b642c99f80..807d62547337 100644
--- a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
+++ b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
@@ -527,6 +527,7 @@ class ARMAsmParser : public MCTargetAsmParser {
OperandMatchResultTy parseCoprocRegOperand(OperandVector &);
OperandMatchResultTy parseCoprocOptionOperand(OperandVector &);
OperandMatchResultTy parseMemBarrierOptOperand(OperandVector &);
+ OperandMatchResultTy parseTraceSyncBarrierOptOperand(OperandVector &);
OperandMatchResultTy parseInstSyncBarrierOptOperand(OperandVector &);
OperandMatchResultTy parseProcIFlagsOperand(OperandVector &);
OperandMatchResultTy parseMSRMaskOperand(OperandVector &);
@@ -561,6 +562,8 @@ class ARMAsmParser : public MCTargetAsmParser {
bool shouldOmitPredicateOperand(StringRef Mnemonic, OperandVector &Operands);
bool isITBlockTerminator(MCInst &Inst) const;
void fixupGNULDRDAlias(StringRef Mnemonic, OperandVector &Operands);
+ bool validateLDRDSTRD(MCInst &Inst, const OperandVector &Operands,
+ bool Load, bool ARMMode, bool Writeback);
public:
enum ARMMatchResultTy {
@@ -644,6 +647,7 @@ class ARMOperand : public MCParsedAsmOperand {
k_Immediate,
k_MemBarrierOpt,
k_InstSyncBarrierOpt,
+ k_TraceSyncBarrierOpt,
k_Memory,
k_PostIndexRegister,
k_MSRMask,
@@ -694,6 +698,10 @@ class ARMOperand : public MCParsedAsmOperand {
ARM_ISB::InstSyncBOpt Val;
};
+ struct TSBOptOp {
+ ARM_TSB::TraceSyncBOpt Val;
+ };
+
struct IFlagsOp {
ARM_PROC::IFlags Val;
};
@@ -790,6 +798,7 @@ class ARMOperand : public MCParsedAsmOperand {
struct CoprocOptionOp CoprocOption;
struct MBOptOp MBOpt;
struct ISBOptOp ISBOpt;
+ struct TSBOptOp TSBOpt;
struct ITMaskOp ITMask;
struct IFlagsOp IFlags;
struct MMaskOp MMask;
@@ -879,6 +888,11 @@ public:
return ISBOpt.Val;
}
+ ARM_TSB::TraceSyncBOpt getTraceSyncBarrierOpt() const {
+ assert(Kind == k_TraceSyncBarrierOpt && "Invalid access!");
+ return TSBOpt.Val;
+ }
+
ARM_PROC::IFlags getProcIFlags() const {
assert(Kind == k_ProcIFlags && "Invalid access!");
return IFlags.Val;
@@ -1028,7 +1042,12 @@ public:
if (!isImm()) return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
- int64_t Value = -CE->getValue();
+ // isImm0_4095Neg is used with 32-bit immediates only.
+ // 32-bit immediates are zero extended to 64-bit when parsed,
+ // thus simple -CE->getValue() results in a big negative number,
+ // not a small positive number as intended
+ if ((CE->getValue() >> 32) > 0) return false;
+ uint32_t Value = -static_cast<uint32_t>(CE->getValue());
return Value > 0 && Value < 4096;
}
@@ -1150,10 +1169,31 @@ public:
bool isToken() const override { return Kind == k_Token; }
bool isMemBarrierOpt() const { return Kind == k_MemBarrierOpt; }
bool isInstSyncBarrierOpt() const { return Kind == k_InstSyncBarrierOpt; }
- bool isMem() const override { return Kind == k_Memory; }
+ bool isTraceSyncBarrierOpt() const { return Kind == k_TraceSyncBarrierOpt; }
+ bool isMem() const override {
+ if (Kind != k_Memory)
+ return false;
+ if (Memory.BaseRegNum &&
+ !ARMMCRegisterClasses[ARM::GPRRegClassID].contains(Memory.BaseRegNum))
+ return false;
+ if (Memory.OffsetRegNum &&
+ !ARMMCRegisterClasses[ARM::GPRRegClassID].contains(Memory.OffsetRegNum))
+ return false;
+ return true;
+ }
bool isShifterImm() const { return Kind == k_ShifterImmediate; }
- bool isRegShiftedReg() const { return Kind == k_ShiftedRegister; }
- bool isRegShiftedImm() const { return Kind == k_ShiftedImmediate; }
+ bool isRegShiftedReg() const {
+ return Kind == k_ShiftedRegister &&
+ ARMMCRegisterClasses[ARM::GPRRegClassID].contains(
+ RegShiftedReg.SrcReg) &&
+ ARMMCRegisterClasses[ARM::GPRRegClassID].contains(
+ RegShiftedReg.ShiftReg);
+ }
+ bool isRegShiftedImm() const {
+ return Kind == k_ShiftedImmediate &&
+ ARMMCRegisterClasses[ARM::GPRRegClassID].contains(
+ RegShiftedImm.SrcReg);
+ }
bool isRotImm() const { return Kind == k_RotateImmediate; }
bool isModImm() const { return Kind == k_ModifiedImmediate; }
@@ -1192,9 +1232,12 @@ public:
bool isConstantPoolImm() const { return Kind == k_ConstantPoolImmediate; }
bool isBitfield() const { return Kind == k_BitfieldDescriptor; }
- bool isPostIdxRegShifted() const { return Kind == k_PostIndexRegister; }
+ bool isPostIdxRegShifted() const {
+ return Kind == k_PostIndexRegister &&
+ ARMMCRegisterClasses[ARM::GPRRegClassID].contains(PostIdxReg.RegNum);
+ }
bool isPostIdxReg() const {
- return Kind == k_PostIndexRegister && PostIdxReg.ShiftTy ==ARM_AM::no_shift;
+ return isPostIdxRegShifted() && PostIdxReg.ShiftTy == ARM_AM::no_shift;
}
bool isMemNoOffset(bool alignOK = false, unsigned Alignment = 0) const {
if (!isMem())
@@ -1331,10 +1374,10 @@ public:
}
bool isAM3Offset() const {
- if (Kind != k_Immediate && Kind != k_PostIndexRegister)
+ if (isPostIdxReg())
+ return true;
+ if (!isImm())
return false;
- if (Kind == k_PostIndexRegister)
- return PostIdxReg.ShiftTy == ARM_AM::no_shift;
// Immediate offset in range [-255, 255].
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (!CE) return false;
@@ -1834,7 +1877,22 @@ public:
return ARM_AM::isNEONi32splat(~Value);
}
- bool isNEONByteReplicate(unsigned NumBytes) const {
+ static bool isValidNEONi32vmovImm(int64_t Value) {
+ // i32 value with set bits only in one byte X000, 0X00, 00X0, or 000X,
+ // for VMOV/VMVN only, 00Xf or 0Xff are also accepted.
+ return ((Value & 0xffffffffffffff00) == 0) ||
+ ((Value & 0xffffffffffff00ff) == 0) ||
+ ((Value & 0xffffffffff00ffff) == 0) ||
+ ((Value & 0xffffffff00ffffff) == 0) ||
+ ((Value & 0xffffffffffff00ff) == 0xff) ||
+ ((Value & 0xffffffffff00ffff) == 0xffff);
+ }
+
+ bool isNEONReplicate(unsigned Width, unsigned NumElems, bool Inv) const {
+ assert((Width == 8 || Width == 16 || Width == 32) &&
+ "Invalid element width");
+ assert(NumElems * Width <= 64 && "Invalid result width");
+
if (!isImm())
return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
@@ -1844,18 +1902,49 @@ public:
int64_t Value = CE->getValue();
if (!Value)
return false; // Don't bother with zero.
+ if (Inv)
+ Value = ~Value;
- unsigned char B = Value & 0xff;
- for (unsigned i = 1; i < NumBytes; ++i) {
- Value >>= 8;
- if ((Value & 0xff) != B)
+ uint64_t Mask = (1ull << Width) - 1;
+ uint64_t Elem = Value & Mask;
+ if (Width == 16 && (Elem & 0x00ff) != 0 && (Elem & 0xff00) != 0)
+ return false;
+ if (Width == 32 && !isValidNEONi32vmovImm(Elem))
+ return false;
+
+ for (unsigned i = 1; i < NumElems; ++i) {
+ Value >>= Width;
+ if ((Value & Mask) != Elem)
return false;
}
return true;
}
- bool isNEONi16ByteReplicate() const { return isNEONByteReplicate(2); }
- bool isNEONi32ByteReplicate() const { return isNEONByteReplicate(4); }
+ bool isNEONByteReplicate(unsigned NumBytes) const {
+ return isNEONReplicate(8, NumBytes, false);
+ }
+
+ static void checkNeonReplicateArgs(unsigned FromW, unsigned ToW) {
+ assert((FromW == 8 || FromW == 16 || FromW == 32) &&
+ "Invalid source width");
+ assert((ToW == 16 || ToW == 32 || ToW == 64) &&
+ "Invalid destination width");
+ assert(FromW < ToW && "ToW is not less than FromW");
+ }
+
+ template<unsigned FromW, unsigned ToW>
+ bool isNEONmovReplicate() const {
+ checkNeonReplicateArgs(FromW, ToW);
+ if (ToW == 64 && isNEONi64splat())
+ return false;
+ return isNEONReplicate(FromW, ToW / FromW, false);
+ }
+
+ template<unsigned FromW, unsigned ToW>
+ bool isNEONinvReplicate() const {
+ checkNeonReplicateArgs(FromW, ToW);
+ return isNEONReplicate(FromW, ToW / FromW, true);
+ }
bool isNEONi32vmov() const {
if (isNEONByteReplicate(4))
@@ -1866,16 +1955,7 @@ public:
// Must be a constant.
if (!CE)
return false;
- int64_t Value = CE->getValue();
- // i32 value with set bits only in one byte X000, 0X00, 00X0, or 000X,
- // for VMOV/VMVN only, 00Xf or 0Xff are also accepted.
- // FIXME: This is probably wrong and a copy and paste from previous example
- return (Value >= 0 && Value < 256) ||
- (Value >= 0x0100 && Value <= 0xff00) ||
- (Value >= 0x010000 && Value <= 0xff0000) ||
- (Value >= 0x01000000 && Value <= 0xff000000) ||
- (Value >= 0x01ff && Value <= 0xffff && (Value & 0xff) == 0xff) ||
- (Value >= 0x01ffff && Value <= 0xffffff && (Value & 0xffff) == 0xffff);
+ return isValidNEONi32vmovImm(CE->getValue());
}
bool isNEONi32vmovNeg() const {
@@ -1883,16 +1963,7 @@ public:
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
// Must be a constant.
if (!CE) return false;
- int64_t Value = ~CE->getValue();
- // i32 value with set bits only in one byte X000, 0X00, 00X0, or 000X,
- // for VMOV/VMVN only, 00Xf or 0Xff are also accepted.
- // FIXME: This is probably wrong and a copy and paste from previous example
- return (Value >= 0 && Value < 256) ||
- (Value >= 0x0100 && Value <= 0xff00) ||
- (Value >= 0x010000 && Value <= 0xff0000) ||
- (Value >= 0x01000000 && Value <= 0xff000000) ||
- (Value >= 0x01ff && Value <= 0xffff && (Value & 0xff) == 0xff) ||
- (Value >= 0x01ffff && Value <= 0xffffff && (Value & 0xffff) == 0xffff);
+ return isValidNEONi32vmovImm(~CE->getValue());
}
bool isNEONi64splat() const {
@@ -2189,7 +2260,7 @@ public:
// The operand is actually an imm0_4095, but we have its
// negation in the assembly source, so twiddle it here.
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
- Inst.addOperand(MCOperand::createImm(-CE->getValue()));
+ Inst.addOperand(MCOperand::createImm(-(uint32_t)CE->getValue()));
}
void addUnsignedOffset_b8s2Operands(MCInst &Inst, unsigned N) const {
@@ -2234,6 +2305,11 @@ public:
Inst.addOperand(MCOperand::createImm(unsigned(getInstSyncBarrierOpt())));
}
+ void addTraceSyncBarrierOptOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ Inst.addOperand(MCOperand::createImm(unsigned(getTraceSyncBarrierOpt())));
+ }
+
void addMemNoOffsetOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
Inst.addOperand(MCOperand::createReg(Memory.BaseRegNum));
@@ -2710,62 +2786,87 @@ public:
Inst.addOperand(MCOperand::createImm(Value));
}
- void addNEONinvByteReplicateOperands(MCInst &Inst, unsigned N) const {
- assert(N == 1 && "Invalid number of operands!");
+ void addNEONi8ReplicateOperands(MCInst &Inst, bool Inv) const {
// The immediate encodes the type of constant as well as the value.
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
- unsigned Value = CE->getValue();
assert((Inst.getOpcode() == ARM::VMOVv8i8 ||
Inst.getOpcode() == ARM::VMOVv16i8) &&
- "All vmvn instructions that wants to replicate non-zero byte "
- "always must be replaced with VMOVv8i8 or VMOVv16i8.");
- unsigned B = ((~Value) & 0xff);
+ "All instructions that wants to replicate non-zero byte "
+ "always must be replaced with VMOVv8i8 or VMOVv16i8.");
+ unsigned Value = CE->getValue();
+ if (Inv)
+ Value = ~Value;
+ unsigned B = Value & 0xff;
B |= 0xe00; // cmode = 0b1110
Inst.addOperand(MCOperand::createImm(B));
}
- void addNEONi32vmovOperands(MCInst &Inst, unsigned N) const {
+ void addNEONinvi8ReplicateOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
- // The immediate encodes the type of constant as well as the value.
- const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
- unsigned Value = CE->getValue();
+ addNEONi8ReplicateOperands(Inst, true);
+ }
+
+ static unsigned encodeNeonVMOVImmediate(unsigned Value) {
if (Value >= 256 && Value <= 0xffff)
Value = (Value >> 8) | ((Value & 0xff) ? 0xc00 : 0x200);
else if (Value > 0xffff && Value <= 0xffffff)
Value = (Value >> 16) | ((Value & 0xff) ? 0xd00 : 0x400);
else if (Value > 0xffffff)
Value = (Value >> 24) | 0x600;
- Inst.addOperand(MCOperand::createImm(Value));
+ return Value;
}
- void addNEONvmovByteReplicateOperands(MCInst &Inst, unsigned N) const {
+ void addNEONi32vmovOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
// The immediate encodes the type of constant as well as the value.
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
- unsigned Value = CE->getValue();
- assert((Inst.getOpcode() == ARM::VMOVv8i8 ||
- Inst.getOpcode() == ARM::VMOVv16i8) &&
- "All instructions that wants to replicate non-zero byte "
- "always must be replaced with VMOVv8i8 or VMOVv16i8.");
- unsigned B = Value & 0xff;
- B |= 0xe00; // cmode = 0b1110
- Inst.addOperand(MCOperand::createImm(B));
+ unsigned Value = encodeNeonVMOVImmediate(CE->getValue());
+ Inst.addOperand(MCOperand::createImm(Value));
+ }
+
+ void addNEONvmovi8ReplicateOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ addNEONi8ReplicateOperands(Inst, false);
+ }
+
+ void addNEONvmovi16ReplicateOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
+ assert((Inst.getOpcode() == ARM::VMOVv4i16 ||
+ Inst.getOpcode() == ARM::VMOVv8i16 ||
+ Inst.getOpcode() == ARM::VMVNv4i16 ||
+ Inst.getOpcode() == ARM::VMVNv8i16) &&
+ "All instructions that want to replicate non-zero half-word "
+ "always must be replaced with V{MOV,MVN}v{4,8}i16.");
+ uint64_t Value = CE->getValue();
+ unsigned Elem = Value & 0xffff;
+ if (Elem >= 256)
+ Elem = (Elem >> 8) | 0x200;
+ Inst.addOperand(MCOperand::createImm(Elem));
}
void addNEONi32vmovNegOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
// The immediate encodes the type of constant as well as the value.
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
- unsigned Value = ~CE->getValue();
- if (Value >= 256 && Value <= 0xffff)
- Value = (Value >> 8) | ((Value & 0xff) ? 0xc00 : 0x200);
- else if (Value > 0xffff && Value <= 0xffffff)
- Value = (Value >> 16) | ((Value & 0xff) ? 0xd00 : 0x400);
- else if (Value > 0xffffff)
- Value = (Value >> 24) | 0x600;
+ unsigned Value = encodeNeonVMOVImmediate(~CE->getValue());
Inst.addOperand(MCOperand::createImm(Value));
}
+ void addNEONvmovi32ReplicateOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
+ assert((Inst.getOpcode() == ARM::VMOVv2i32 ||
+ Inst.getOpcode() == ARM::VMOVv4i32 ||
+ Inst.getOpcode() == ARM::VMVNv2i32 ||
+ Inst.getOpcode() == ARM::VMVNv4i32) &&
+ "All instructions that want to replicate non-zero word "
+ "always must be replaced with V{MOV,MVN}v{2,4}i32.");
+ uint64_t Value = CE->getValue();
+ unsigned Elem = encodeNeonVMOVImmediate(Value & 0xffffffff);
+ Inst.addOperand(MCOperand::createImm(Elem));
+ }
+
void addNEONi64splatOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
// The immediate encodes the type of constant as well as the value.
@@ -3064,6 +3165,15 @@ public:
return Op;
}
+ static std::unique_ptr<ARMOperand>
+ CreateTraceSyncBarrierOpt(ARM_TSB::TraceSyncBOpt Opt, SMLoc S) {
+ auto Op = make_unique<ARMOperand>(k_TraceSyncBarrierOpt);
+ Op->TSBOpt.Val = Opt;
+ Op->StartLoc = S;
+ Op->EndLoc = S;
+ return Op;
+ }
+
static std::unique_ptr<ARMOperand> CreateProcIFlags(ARM_PROC::IFlags IFlags,
SMLoc S) {
auto Op = make_unique<ARMOperand>(k_ProcIFlags);
@@ -3133,6 +3243,9 @@ void ARMOperand::print(raw_ostream &OS) const {
case k_InstSyncBarrierOpt:
OS << "<ARM_ISB::" << InstSyncBOptToString(getInstSyncBarrierOpt()) << ">";
break;
+ case k_TraceSyncBarrierOpt:
+ OS << "<ARM_TSB::" << TraceSyncBOptToString(getTraceSyncBarrierOpt()) << ">";
+ break;
case k_Memory:
OS << "<memory "
<< " base:" << Memory.BaseRegNum;
@@ -4122,6 +4235,24 @@ ARMAsmParser::parseMemBarrierOptOperand(OperandVector &Operands) {
return MatchOperand_Success;
}
+OperandMatchResultTy
+ARMAsmParser::parseTraceSyncBarrierOptOperand(OperandVector &Operands) {
+ MCAsmParser &Parser = getParser();
+ SMLoc S = Parser.getTok().getLoc();
+ const AsmToken &Tok = Parser.getTok();
+
+ if (Tok.isNot(AsmToken::Identifier))
+ return MatchOperand_NoMatch;
+
+ if (!Tok.getString().equals_lower("csync"))
+ return MatchOperand_NoMatch;
+
+ Parser.Lex(); // Eat identifier token.
+
+ Operands.push_back(ARMOperand::CreateTraceSyncBarrierOpt(ARM_TSB::CSYNC, S));
+ return MatchOperand_Success;
+}
+
/// parseInstSyncBarrierOptOperand - Try to parse ISB inst sync barrier options.
OperandMatchResultTy
ARMAsmParser::parseInstSyncBarrierOptOperand(OperandVector &Operands) {
@@ -4215,6 +4346,18 @@ ARMAsmParser::parseMSRMaskOperand(OperandVector &Operands) {
MCAsmParser &Parser = getParser();
SMLoc S = Parser.getTok().getLoc();
const AsmToken &Tok = Parser.getTok();
+
+ if (Tok.is(AsmToken::Integer)) {
+ int64_t Val = Tok.getIntVal();
+ if (Val > 255 || Val < 0) {
+ return MatchOperand_NoMatch;
+ }
+ unsigned SYSmvalue = Val & 0xFF;
+ Parser.Lex();
+ Operands.push_back(ARMOperand::CreateMSRMask(SYSmvalue, S));
+ return MatchOperand_Success;
+ }
+
if (!Tok.is(AsmToken::Identifier))
return MatchOperand_NoMatch;
StringRef Mask = Tok.getString();
@@ -5450,7 +5593,7 @@ bool ARMAsmParser::parsePrefix(ARMMCExpr::VariantKind &RefKind) {
return false;
}
-/// \brief Given a mnemonic, split out possible predication code and carry
+/// Given a mnemonic, split out possible predication code and carry
/// setting letters to form a canonical mnemonic and flags.
//
// FIXME: Would be nice to autogen this.
@@ -5541,7 +5684,7 @@ StringRef ARMAsmParser::splitMnemonic(StringRef Mnemonic,
return Mnemonic;
}
-/// \brief Given a canonical mnemonic, determine if the instruction ever allows
+/// Given a canonical mnemonic, determine if the instruction ever allows
/// inclusion of carry set or predication code operands.
//
// FIXME: It would be nice to autogen this.
@@ -5585,6 +5728,7 @@ void ARMAsmParser::getMnemonicAcceptInfo(StringRef Mnemonic, StringRef FullInst,
Mnemonic != "isb" && Mnemonic != "pld" && Mnemonic != "pli" &&
Mnemonic != "pldw" && Mnemonic != "ldc2" && Mnemonic != "ldc2l" &&
Mnemonic != "stc2" && Mnemonic != "stc2l" &&
+ Mnemonic != "tsb" &&
!Mnemonic.startswith("rfe") && !Mnemonic.startswith("srs");
} else if (isThumbOne()) {
if (hasV6MOps())
@@ -5595,7 +5739,7 @@ void ARMAsmParser::getMnemonicAcceptInfo(StringRef Mnemonic, StringRef FullInst,
CanAcceptPredicationCode = true;
}
-// \brief Some Thumb instructions have two operand forms that are not
+// Some Thumb instructions have two operand forms that are not
// available as three operand, convert to two operand form if possible.
//
// FIXME: We would really like to be able to tablegen'erate this.
@@ -6214,6 +6358,65 @@ bool ARMAsmParser::validatetSTMRegList(const MCInst &Inst,
return false;
}
+bool ARMAsmParser::validateLDRDSTRD(MCInst &Inst,
+ const OperandVector &Operands,
+ bool Load, bool ARMMode, bool Writeback) {
+ unsigned RtIndex = Load || !Writeback ? 0 : 1;
+ unsigned Rt = MRI->getEncodingValue(Inst.getOperand(RtIndex).getReg());
+ unsigned Rt2 = MRI->getEncodingValue(Inst.getOperand(RtIndex + 1).getReg());
+
+ if (ARMMode) {
+ // Rt can't be R14.
+ if (Rt == 14)
+ return Error(Operands[3]->getStartLoc(),
+ "Rt can't be R14");
+
+ // Rt must be even-numbered.
+ if ((Rt & 1) == 1)
+ return Error(Operands[3]->getStartLoc(),
+ "Rt must be even-numbered");
+
+ // Rt2 must be Rt + 1.
+ if (Rt2 != Rt + 1) {
+ if (Load)
+ return Error(Operands[3]->getStartLoc(),
+ "destination operands must be sequential");
+ else
+ return Error(Operands[3]->getStartLoc(),
+ "source operands must be sequential");
+ }
+
+ // FIXME: Diagnose m == 15
+ // FIXME: Diagnose ldrd with m == t || m == t2.
+ }
+
+ if (!ARMMode && Load) {
+ if (Rt2 == Rt)
+ return Error(Operands[3]->getStartLoc(),
+ "destination operands can't be identical");
+ }
+
+ if (Writeback) {
+ unsigned Rn = MRI->getEncodingValue(Inst.getOperand(3).getReg());
+
+ if (Rn == Rt || Rn == Rt2) {
+ if (Load)
+ return Error(Operands[3]->getStartLoc(),
+ "base register needs to be different from destination "
+ "registers");
+ else
+ return Error(Operands[3]->getStartLoc(),
+ "source register and base register can't be identical");
+ }
+
+ // FIXME: Diagnose ldrd/strd with writeback and n == 15.
+ // (Except the immediate form of ldrd?)
+ }
+
+ return false;
+}
+
+
// FIXME: We would really like to be able to tablegen'erate this.
bool ARMAsmParser::validateInstruction(MCInst &Inst,
const OperandVector &Operands) {
@@ -6227,7 +6430,8 @@ bool ARMAsmParser::validateInstruction(MCInst &Inst,
// The instruction must be predicable.
if (!MCID.isPredicable())
return Error(Loc, "instructions in IT block must be predicable");
- unsigned Cond = Inst.getOperand(MCID.findFirstPredOperandIdx()).getImm();
+ ARMCC::CondCodes Cond = ARMCC::CondCodes(
+ Inst.getOperand(MCID.findFirstPredOperandIdx()).getImm());
if (Cond != currentITCond()) {
// Find the condition code Operand to get its SMLoc information.
SMLoc CondLoc;
@@ -6235,9 +6439,9 @@ bool ARMAsmParser::validateInstruction(MCInst &Inst,
if (static_cast<ARMOperand &>(*Operands[I]).isCondCode())
CondLoc = Operands[I]->getStartLoc();
return Error(CondLoc, "incorrect condition in IT block; got '" +
- StringRef(ARMCondCodeToString(ARMCC::CondCodes(Cond))) +
- "', but expected '" +
- ARMCondCodeToString(ARMCC::CondCodes(currentITCond())) + "'");
+ StringRef(ARMCondCodeToString(Cond)) +
+ "', but expected '" +
+ ARMCondCodeToString(currentITCond()) + "'");
}
// Check for non-'al' condition codes outside of the IT block.
} else if (isThumbTwo() && MCID.isPredicable() &&
@@ -6259,51 +6463,43 @@ bool ARMAsmParser::validateInstruction(MCInst &Inst,
const unsigned Opcode = Inst.getOpcode();
switch (Opcode) {
- case ARM::LDRD:
- case ARM::LDRD_PRE:
- case ARM::LDRD_POST: {
- const unsigned RtReg = Inst.getOperand(0).getReg();
-
- // Rt can't be R14.
- if (RtReg == ARM::LR)
- return Error(Operands[3]->getStartLoc(),
- "Rt can't be R14");
-
- const unsigned Rt = MRI->getEncodingValue(RtReg);
- // Rt must be even-numbered.
- if ((Rt & 1) == 1)
- return Error(Operands[3]->getStartLoc(),
- "Rt must be even-numbered");
-
- // Rt2 must be Rt + 1.
- const unsigned Rt2 = MRI->getEncodingValue(Inst.getOperand(1).getReg());
- if (Rt2 != Rt + 1)
- return Error(Operands[3]->getStartLoc(),
- "destination operands must be sequential");
-
- if (Opcode == ARM::LDRD_PRE || Opcode == ARM::LDRD_POST) {
- const unsigned Rn = MRI->getEncodingValue(Inst.getOperand(3).getReg());
- // For addressing modes with writeback, the base register needs to be
- // different from the destination registers.
- if (Rn == Rt || Rn == Rt2)
- return Error(Operands[3]->getStartLoc(),
- "base register needs to be different from destination "
- "registers");
- }
+ case ARM::t2IT: {
+ // Encoding is unpredictable if it ever results in a notional 'NV'
+ // predicate. Since we don't parse 'NV' directly this means an 'AL'
+ // predicate with an "else" mask bit.
+ unsigned Cond = Inst.getOperand(0).getImm();
+ unsigned Mask = Inst.getOperand(1).getImm();
- return false;
+ // Mask hasn't been modified to the IT instruction encoding yet so
+ // conditions only allowing a 't' are a block of 1s starting at bit 3
+ // followed by all 0s. Easiest way is to just list the 4 possibilities.
+ if (Cond == ARMCC::AL && Mask != 8 && Mask != 12 && Mask != 14 &&
+ Mask != 15)
+ return Error(Loc, "unpredictable IT predicate sequence");
+ break;
}
+ case ARM::LDRD:
+ if (validateLDRDSTRD(Inst, Operands, /*Load*/true, /*ARMMode*/true,
+ /*Writeback*/false))
+ return true;
+ break;
+ case ARM::LDRD_PRE:
+ case ARM::LDRD_POST:
+ if (validateLDRDSTRD(Inst, Operands, /*Load*/true, /*ARMMode*/true,
+ /*Writeback*/true))
+ return true;
+ break;
case ARM::t2LDRDi8:
+ if (validateLDRDSTRD(Inst, Operands, /*Load*/true, /*ARMMode*/false,
+ /*Writeback*/false))
+ return true;
+ break;
case ARM::t2LDRD_PRE:
- case ARM::t2LDRD_POST: {
- // Rt2 must be different from Rt.
- unsigned Rt = MRI->getEncodingValue(Inst.getOperand(0).getReg());
- unsigned Rt2 = MRI->getEncodingValue(Inst.getOperand(1).getReg());
- if (Rt2 == Rt)
- return Error(Operands[3]->getStartLoc(),
- "destination operands can't be identical");
- return false;
- }
+ case ARM::t2LDRD_POST:
+ if (validateLDRDSTRD(Inst, Operands, /*Load*/true, /*ARMMode*/false,
+ /*Writeback*/true))
+ return true;
+ break;
case ARM::t2BXJ: {
const unsigned RmReg = Inst.getOperand(0).getReg();
// Rm = SP is no longer unpredictable in v8-A
@@ -6312,35 +6508,39 @@ bool ARMAsmParser::validateInstruction(MCInst &Inst,
"r13 (SP) is an unpredictable operand to BXJ");
return false;
}
- case ARM::STRD: {
- // Rt2 must be Rt + 1.
- unsigned Rt = MRI->getEncodingValue(Inst.getOperand(0).getReg());
- unsigned Rt2 = MRI->getEncodingValue(Inst.getOperand(1).getReg());
- if (Rt2 != Rt + 1)
- return Error(Operands[3]->getStartLoc(),
- "source operands must be sequential");
- return false;
- }
+ case ARM::STRD:
+ if (validateLDRDSTRD(Inst, Operands, /*Load*/false, /*ARMMode*/true,
+ /*Writeback*/false))
+ return true;
+ break;
case ARM::STRD_PRE:
- case ARM::STRD_POST: {
- // Rt2 must be Rt + 1.
- unsigned Rt = MRI->getEncodingValue(Inst.getOperand(1).getReg());
- unsigned Rt2 = MRI->getEncodingValue(Inst.getOperand(2).getReg());
- if (Rt2 != Rt + 1)
- return Error(Operands[3]->getStartLoc(),
- "source operands must be sequential");
- return false;
- }
+ case ARM::STRD_POST:
+ if (validateLDRDSTRD(Inst, Operands, /*Load*/false, /*ARMMode*/true,
+ /*Writeback*/true))
+ return true;
+ break;
+ case ARM::t2STRD_PRE:
+ case ARM::t2STRD_POST:
+ if (validateLDRDSTRD(Inst, Operands, /*Load*/false, /*ARMMode*/false,
+ /*Writeback*/true))
+ return true;
+ break;
case ARM::STR_PRE_IMM:
case ARM::STR_PRE_REG:
+ case ARM::t2STR_PRE:
case ARM::STR_POST_IMM:
case ARM::STR_POST_REG:
+ case ARM::t2STR_POST:
case ARM::STRH_PRE:
+ case ARM::t2STRH_PRE:
case ARM::STRH_POST:
+ case ARM::t2STRH_POST:
case ARM::STRB_PRE_IMM:
case ARM::STRB_PRE_REG:
+ case ARM::t2STRB_PRE:
case ARM::STRB_POST_IMM:
- case ARM::STRB_POST_REG: {
+ case ARM::STRB_POST_REG:
+ case ARM::t2STRB_POST: {
// Rt must be different from Rn.
const unsigned Rt = MRI->getEncodingValue(Inst.getOperand(1).getReg());
const unsigned Rn = MRI->getEncodingValue(Inst.getOperand(2).getReg());
@@ -6352,18 +6552,28 @@ bool ARMAsmParser::validateInstruction(MCInst &Inst,
}
case ARM::LDR_PRE_IMM:
case ARM::LDR_PRE_REG:
+ case ARM::t2LDR_PRE:
case ARM::LDR_POST_IMM:
case ARM::LDR_POST_REG:
+ case ARM::t2LDR_POST:
case ARM::LDRH_PRE:
+ case ARM::t2LDRH_PRE:
case ARM::LDRH_POST:
+ case ARM::t2LDRH_POST:
case ARM::LDRSH_PRE:
+ case ARM::t2LDRSH_PRE:
case ARM::LDRSH_POST:
+ case ARM::t2LDRSH_POST:
case ARM::LDRB_PRE_IMM:
case ARM::LDRB_PRE_REG:
+ case ARM::t2LDRB_PRE:
case ARM::LDRB_POST_IMM:
case ARM::LDRB_POST_REG:
+ case ARM::t2LDRB_POST:
case ARM::LDRSB_PRE:
- case ARM::LDRSB_POST: {
+ case ARM::t2LDRSB_PRE:
+ case ARM::LDRSB_POST:
+ case ARM::t2LDRSB_POST: {
// Rt must be different from Rn.
const unsigned Rt = MRI->getEncodingValue(Inst.getOperand(0).getReg());
const unsigned Rn = MRI->getEncodingValue(Inst.getOperand(2).getReg());
@@ -6374,7 +6584,9 @@ bool ARMAsmParser::validateInstruction(MCInst &Inst,
return false;
}
case ARM::SBFX:
- case ARM::UBFX: {
+ case ARM::t2SBFX:
+ case ARM::UBFX:
+ case ARM::t2UBFX: {
// Width must be in range [1, 32-lsb].
unsigned LSB = Inst.getOperand(2).getImm();
unsigned Widthm1 = Inst.getOperand(3).getImm();
@@ -6592,19 +6804,40 @@ bool ARMAsmParser::validateInstruction(MCInst &Inst,
break;
}
case ARM::HINT:
- case ARM::t2HINT:
- if (hasRAS()) {
- // ESB is not predicable (pred must be AL)
- unsigned Imm8 = Inst.getOperand(0).getImm();
- unsigned Pred = Inst.getOperand(1).getImm();
- if (Imm8 == 0x10 && Pred != ARMCC::AL)
- return Error(Operands[1]->getStartLoc(), "instruction 'esb' is not "
- "predicable, but condition "
- "code specified");
- }
- // Without the RAS extension, this behaves as any other unallocated hint.
+ case ARM::t2HINT: {
+ unsigned Imm8 = Inst.getOperand(0).getImm();
+ unsigned Pred = Inst.getOperand(1).getImm();
+ // ESB is not predicable (pred must be AL). Without the RAS extension, this
+ // behaves as any other unallocated hint.
+ if (Imm8 == 0x10 && Pred != ARMCC::AL && hasRAS())
+ return Error(Operands[1]->getStartLoc(), "instruction 'esb' is not "
+ "predicable, but condition "
+ "code specified");
+ if (Imm8 == 0x14 && Pred != ARMCC::AL)
+ return Error(Operands[1]->getStartLoc(), "instruction 'csdb' is not "
+ "predicable, but condition "
+ "code specified");
+ break;
+ }
+ case ARM::VMOVRRS: {
+ // Source registers must be sequential.
+ const unsigned Sm = MRI->getEncodingValue(Inst.getOperand(2).getReg());
+ const unsigned Sm1 = MRI->getEncodingValue(Inst.getOperand(3).getReg());
+ if (Sm1 != Sm + 1)
+ return Error(Operands[5]->getStartLoc(),
+ "source operands must be sequential");
break;
}
+ case ARM::VMOVSRR: {
+ // Destination registers must be sequential.
+ const unsigned Sm = MRI->getEncodingValue(Inst.getOperand(0).getReg());
+ const unsigned Sm1 = MRI->getEncodingValue(Inst.getOperand(1).getReg());
+ if (Sm1 != Sm + 1)
+ return Error(Operands[3]->getStartLoc(),
+ "destination operands must be sequential");
+ break;
+ }
+ }
return false;
}
@@ -10173,10 +10406,11 @@ ARMAsmParser::FilterNearMisses(SmallVectorImpl<NearMissInfo> &NearMissesIn,
Message.Message = "too many operands for instruction";
} else {
Message.Message = "invalid operand for instruction";
- DEBUG(dbgs() << "Missing diagnostic string for operand class " <<
- getMatchClassName((MatchClassKind)I.getOperandClass())
- << I.getOperandClass() << ", error " << I.getOperandError()
- << ", opcode " << MII.getName(I.getOpcode()) << "\n");
+ LLVM_DEBUG(
+ dbgs() << "Missing diagnostic string for operand class "
+ << getMatchClassName((MatchClassKind)I.getOperandClass())
+ << I.getOperandClass() << ", error " << I.getOperandError()
+ << ", opcode " << MII.getName(I.getOpcode()) << "\n");
}
NearMissesOut.emplace_back(Message);
break;
@@ -10203,6 +10437,8 @@ ARMAsmParser::FilterNearMisses(SmallVectorImpl<NearMissInfo> &NearMissesIn,
if (!isThumb() && (MissingFeatures & Feature_IsThumb2) &&
(MissingFeatures & ~(Feature_IsThumb2 | Feature_IsThumb)))
break;
+ if (isMClass() && (MissingFeatures & Feature_HasNEON))
+ break;
NearMissMessage Message;
Message.Loc = IDLoc;
diff --git a/lib/Target/ARM/CMakeLists.txt b/lib/Target/ARM/CMakeLists.txt
index 014ac2ae8b48..d635c0add577 100644
--- a/lib/Target/ARM/CMakeLists.txt
+++ b/lib/Target/ARM/CMakeLists.txt
@@ -1,19 +1,20 @@
set(LLVM_TARGET_DEFINITIONS ARM.td)
-tablegen(LLVM ARMGenRegisterBank.inc -gen-register-bank)
+tablegen(LLVM ARMGenAsmMatcher.inc -gen-asm-matcher)
+tablegen(LLVM ARMGenAsmWriter.inc -gen-asm-writer)
+tablegen(LLVM ARMGenCallingConv.inc -gen-callingconv)
+tablegen(LLVM ARMGenDAGISel.inc -gen-dag-isel)
+tablegen(LLVM ARMGenDisassemblerTables.inc -gen-disassembler)
+tablegen(LLVM ARMGenFastISel.inc -gen-fast-isel)
tablegen(LLVM ARMGenGlobalISel.inc -gen-global-isel)
-tablegen(LLVM ARMGenRegisterInfo.inc -gen-register-info)
tablegen(LLVM ARMGenInstrInfo.inc -gen-instr-info)
tablegen(LLVM ARMGenMCCodeEmitter.inc -gen-emitter)
tablegen(LLVM ARMGenMCPseudoLowering.inc -gen-pseudo-lowering)
-tablegen(LLVM ARMGenAsmWriter.inc -gen-asm-writer)
-tablegen(LLVM ARMGenAsmMatcher.inc -gen-asm-matcher)
-tablegen(LLVM ARMGenDAGISel.inc -gen-dag-isel)
-tablegen(LLVM ARMGenFastISel.inc -gen-fast-isel)
-tablegen(LLVM ARMGenCallingConv.inc -gen-callingconv)
+tablegen(LLVM ARMGenRegisterBank.inc -gen-register-bank)
+tablegen(LLVM ARMGenRegisterInfo.inc -gen-register-info)
tablegen(LLVM ARMGenSubtargetInfo.inc -gen-subtarget)
-tablegen(LLVM ARMGenDisassemblerTables.inc -gen-disassembler)
tablegen(LLVM ARMGenSystemRegister.inc -gen-searchable-tables)
+
add_public_tablegen_target(ARMCommonTableGen)
add_llvm_target(ARMCodeGen
@@ -22,6 +23,7 @@ add_llvm_target(ARMCodeGen
ARMBaseInstrInfo.cpp
ARMBaseRegisterInfo.cpp
ARMCallLowering.cpp
+ ARMCodeGenPrepare.cpp
ARMConstantIslandPass.cpp
ARMConstantPoolValue.cpp
ARMExpandPseudoInsts.cpp
@@ -33,6 +35,7 @@ add_llvm_target(ARMCodeGen
ARMISelLowering.cpp
ARMInstrInfo.cpp
ARMLegalizerInfo.cpp
+ ARMParallelDSP.cpp
ARMLoadStoreOptimizer.cpp
ARMMCInstLower.cpp
ARMMachineFunctionInfo.cpp
@@ -55,9 +58,9 @@ add_llvm_target(ARMCodeGen
ARMComputeBlockSize.cpp
)
-add_subdirectory(TargetInfo)
add_subdirectory(AsmParser)
add_subdirectory(Disassembler)
add_subdirectory(InstPrinter)
add_subdirectory(MCTargetDesc)
+add_subdirectory(TargetInfo)
add_subdirectory(Utils)
diff --git a/lib/Target/ARM/Disassembler/ARMDisassembler.cpp b/lib/Target/ARM/Disassembler/ARMDisassembler.cpp
index 53c635877675..4733cf49827e 100644
--- a/lib/Target/ARM/Disassembler/ARMDisassembler.cpp
+++ b/lib/Target/ARM/Disassembler/ARMDisassembler.cpp
@@ -158,6 +158,8 @@ static DecodeStatus DecoderGPRRegisterClass(MCInst &Inst, unsigned RegNo,
uint64_t Address, const void *Decoder);
static DecodeStatus DecodeGPRPairRegisterClass(MCInst &Inst, unsigned RegNo,
uint64_t Address, const void *Decoder);
+static DecodeStatus DecodeHPRRegisterClass(MCInst &Inst, unsigned RegNo,
+ uint64_t Address, const void *Decoder);
static DecodeStatus DecodeSPRRegisterClass(MCInst &Inst, unsigned RegNo,
uint64_t Address, const void *Decoder);
static DecodeStatus DecodeDPRRegisterClass(MCInst &Inst, unsigned RegNo,
@@ -657,6 +659,8 @@ ThumbDisassembler::AddThumbPredicate(MCInst &MI) const {
void ThumbDisassembler::UpdateThumbVFPPredicate(MCInst &MI) const {
unsigned CC;
CC = ITBlock.getITCC();
+ if (CC == 0xF)
+ CC = ARMCC::AL;
if (ITBlock.instrInITBlock())
ITBlock.advanceITState();
@@ -727,10 +731,13 @@ DecodeStatus ThumbDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
// code and mask operands so that we can apply them correctly
// to the subsequent instructions.
if (MI.getOpcode() == ARM::t2IT) {
-
unsigned Firstcond = MI.getOperand(0).getImm();
unsigned Mask = MI.getOperand(1).getImm();
ITBlock.setITState(Firstcond, Mask);
+
+ // An IT instruction that would give a 'NV' predicate is unpredictable.
+ if (Firstcond == ARMCC::AL && !isPowerOf2_32(Mask))
+ CS << "unpredictable IT predicate sequence";
}
return Result;
@@ -996,6 +1003,11 @@ static DecodeStatus DecodeSPRRegisterClass(MCInst &Inst, unsigned RegNo,
return MCDisassembler::Success;
}
+static DecodeStatus DecodeHPRRegisterClass(MCInst &Inst, unsigned RegNo,
+ uint64_t Address, const void *Decoder) {
+ return DecodeSPRRegisterClass(Inst, RegNo, Address, Decoder);
+}
+
static const uint16_t DPRDecoderTable[] = {
ARM::D0, ARM::D1, ARM::D2, ARM::D3,
ARM::D4, ARM::D5, ARM::D6, ARM::D7,
@@ -4142,7 +4154,6 @@ static DecodeStatus DecodeMSRMask(MCInst &Inst, unsigned Val,
case 0x8a: // msplim_ns
case 0x8b: // psplim_ns
case 0x91: // basepri_ns
- case 0x92: // basepri_max_ns
case 0x93: // faultmask_ns
if (!(FeatureBits[ARM::HasV8MMainlineOps]))
return MCDisassembler::Fail;
@@ -4158,7 +4169,9 @@ static DecodeStatus DecodeMSRMask(MCInst &Inst, unsigned Val,
return MCDisassembler::Fail;
break;
default:
- return MCDisassembler::Fail;
+ // Architecturally defined as unpredictable
+ S = MCDisassembler::SoftFail;
+ break;
}
if (Inst.getOpcode() == ARM::t2MSR_M) {
@@ -4198,15 +4211,8 @@ static DecodeStatus DecodeBankedReg(MCInst &Inst, unsigned Val,
// The table of encodings for these banked registers comes from B9.2.3 of the
// ARM ARM. There are patterns, but nothing regular enough to make this logic
// neater. So by fiat, these values are UNPREDICTABLE:
- if (!R) {
- if (SysM == 0x7 || SysM == 0xf || SysM == 0x18 || SysM == 0x19 ||
- SysM == 0x1a || SysM == 0x1b)
- return MCDisassembler::SoftFail;
- } else {
- if (SysM != 0xe && SysM != 0x10 && SysM != 0x12 && SysM != 0x14 &&
- SysM != 0x16 && SysM != 0x1c && SysM != 0x1e)
- return MCDisassembler::SoftFail;
- }
+ if (!ARMBankedReg::lookupBankedRegByEncoding((R << 5) | SysM))
+ return MCDisassembler::Fail;
Inst.addOperand(MCOperand::createImm(Val));
return MCDisassembler::Success;
diff --git a/lib/Target/ARM/Disassembler/LLVMBuild.txt b/lib/Target/ARM/Disassembler/LLVMBuild.txt
index a64a8a970c05..48eef05e4f2d 100644
--- a/lib/Target/ARM/Disassembler/LLVMBuild.txt
+++ b/lib/Target/ARM/Disassembler/LLVMBuild.txt
@@ -19,5 +19,5 @@
type = Library
name = ARMDisassembler
parent = ARM
-required_libraries = ARMDesc ARMInfo MCDisassembler Support
+required_libraries = ARMDesc ARMInfo MCDisassembler Support ARMUtils
add_to_library_groups = ARM
diff --git a/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp b/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp
index 4fc67a4f6eb5..75ed40c18fa2 100644
--- a/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp
+++ b/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp
@@ -13,8 +13,6 @@
#include "ARMInstPrinter.h"
#include "Utils/ARMBaseInfo.h"
-#include "ARMBaseRegisterInfo.h"
-#include "ARMBaseRegisterInfo.h"
#include "MCTargetDesc/ARMAddressingModes.h"
#include "MCTargetDesc/ARMBaseInfo.h"
#include "llvm/MC/MCAsmInfo.h"
@@ -271,6 +269,10 @@ void ARMInstPrinter::printInst(const MCInst *MI, raw_ostream &O,
}
break;
}
+ case ARM::TSB:
+ case ARM::t2TSB:
+ O << "\ttsb\tcsync";
+ return;
}
if (!printAliasInstr(MI, STI, O))
@@ -698,6 +700,13 @@ void ARMInstPrinter::printInstSyncBOption(const MCInst *MI, unsigned OpNum,
O << ARM_ISB::InstSyncBOptToString(val);
}
+void ARMInstPrinter::printTraceSyncBOption(const MCInst *MI, unsigned OpNum,
+ const MCSubtargetInfo &STI,
+ raw_ostream &O) {
+ unsigned val = MI->getOperand(OpNum).getImm();
+ O << ARM_TSB::TraceSyncBOptToString(val);
+}
+
void ARMInstPrinter::printShiftImmOperand(const MCInst *MI, unsigned OpNum,
const MCSubtargetInfo &STI,
raw_ostream &O) {
@@ -825,7 +834,8 @@ void ARMInstPrinter::printMSRMaskOperand(const MCInst *MI, unsigned OpNum,
return;
}
- llvm_unreachable("Unexpected mask value!");
+ O << SYSm;
+
return;
}
diff --git a/lib/Target/ARM/InstPrinter/ARMInstPrinter.h b/lib/Target/ARM/InstPrinter/ARMInstPrinter.h
index 7dc311229cca..afc8515136bc 100644
--- a/lib/Target/ARM/InstPrinter/ARMInstPrinter.h
+++ b/lib/Target/ARM/InstPrinter/ARMInstPrinter.h
@@ -94,6 +94,8 @@ public:
const MCSubtargetInfo &STI, raw_ostream &O);
void printInstSyncBOption(const MCInst *MI, unsigned OpNum,
const MCSubtargetInfo &STI, raw_ostream &O);
+ void printTraceSyncBOption(const MCInst *MI, unsigned OpNum,
+ const MCSubtargetInfo &STI, raw_ostream &O);
void printShiftImmOperand(const MCInst *MI, unsigned OpNum,
const MCSubtargetInfo &STI, raw_ostream &O);
void printPKHLSLShiftImm(const MCInst *MI, unsigned OpNum,
diff --git a/lib/Target/ARM/LLVMBuild.txt b/lib/Target/ARM/LLVMBuild.txt
index a450acc5e13a..78d28427f3d9 100644
--- a/lib/Target/ARM/LLVMBuild.txt
+++ b/lib/Target/ARM/LLVMBuild.txt
@@ -31,5 +31,5 @@ has_jit = 1
type = Library
name = ARMCodeGen
parent = ARM
-required_libraries = ARMAsmPrinter ARMDesc ARMInfo Analysis AsmPrinter CodeGen Core MC Scalar SelectionDAG Support Target GlobalISel ARMUtils
+required_libraries = ARMAsmPrinter ARMDesc ARMInfo Analysis AsmPrinter CodeGen Core MC Scalar SelectionDAG Support Target GlobalISel ARMUtils TransformUtils
add_to_library_groups = ARM
diff --git a/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp b/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp
index 1cb9dd44f789..f524a0081301 100644
--- a/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp
+++ b/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp
@@ -31,6 +31,7 @@
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/MCValue.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/EndianStream.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/TargetParser.h"
@@ -155,7 +156,8 @@ const MCFixupKindInfo &ARMAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() &&
"Invalid kind!");
- return (IsLittleEndian ? InfosLE : InfosBE)[Kind - FirstTargetFixupKind];
+ return (Endian == support::little ? InfosLE
+ : InfosBE)[Kind - FirstTargetFixupKind];
}
void ARMAsmBackend::handleAssemblerFlag(MCAssemblerFlag Flag) {
@@ -171,9 +173,10 @@ void ARMAsmBackend::handleAssemblerFlag(MCAssemblerFlag Flag) {
}
}
-unsigned ARMAsmBackend::getRelaxedOpcode(unsigned Op) const {
- bool HasThumb2 = STI->getFeatureBits()[ARM::FeatureThumb2];
- bool HasV8MBaselineOps = STI->getFeatureBits()[ARM::HasV8MBaselineOps];
+unsigned ARMAsmBackend::getRelaxedOpcode(unsigned Op,
+ const MCSubtargetInfo &STI) const {
+ bool HasThumb2 = STI.getFeatureBits()[ARM::FeatureThumb2];
+ bool HasV8MBaselineOps = STI.getFeatureBits()[ARM::HasV8MBaselineOps];
switch (Op) {
default:
@@ -193,8 +196,9 @@ unsigned ARMAsmBackend::getRelaxedOpcode(unsigned Op) const {
}
}
-bool ARMAsmBackend::mayNeedRelaxation(const MCInst &Inst) const {
- if (getRelaxedOpcode(Inst.getOpcode()) != Inst.getOpcode())
+bool ARMAsmBackend::mayNeedRelaxation(const MCInst &Inst,
+ const MCSubtargetInfo &STI) const {
+ if (getRelaxedOpcode(Inst.getOpcode(), STI) != Inst.getOpcode())
return true;
return false;
}
@@ -239,7 +243,7 @@ const char *ARMAsmBackend::reasonForFixupRelaxation(const MCFixup &Fixup,
}
case ARM::fixup_arm_thumb_cb: {
// If we have a Thumb CBZ or CBNZ instruction and its target is the next
- // instruction it is is actually out of range for the instruction.
+ // instruction it is actually out of range for the instruction.
// It will be changed to a NOP.
int64_t Offset = (Value & ~1);
if (Offset == 2)
@@ -261,7 +265,7 @@ bool ARMAsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value,
void ARMAsmBackend::relaxInstruction(const MCInst &Inst,
const MCSubtargetInfo &STI,
MCInst &Res) const {
- unsigned RelaxedOp = getRelaxedOpcode(Inst.getOpcode());
+ unsigned RelaxedOp = getRelaxedOpcode(Inst.getOpcode(), STI);
// Sanity check w/ diagnostic if we get here w/ a bogus instruction.
if (RelaxedOp == Inst.getOpcode()) {
@@ -289,7 +293,7 @@ void ARMAsmBackend::relaxInstruction(const MCInst &Inst,
Res.setOpcode(RelaxedOp);
}
-bool ARMAsmBackend::writeNopData(uint64_t Count, MCObjectWriter *OW) const {
+bool ARMAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count) const {
const uint16_t Thumb1_16bitNopEncoding = 0x46c0; // using MOV r8,r8
const uint16_t Thumb2_16bitNopEncoding = 0xbf00; // NOP
const uint32_t ARMv4_NopEncoding = 0xe1a00000; // using MOV r0,r0
@@ -299,9 +303,9 @@ bool ARMAsmBackend::writeNopData(uint64_t Count, MCObjectWriter *OW) const {
hasNOP() ? Thumb2_16bitNopEncoding : Thumb1_16bitNopEncoding;
uint64_t NumNops = Count / 2;
for (uint64_t i = 0; i != NumNops; ++i)
- OW->write16(nopEncoding);
+ support::endian::write(OS, nopEncoding, Endian);
if (Count & 1)
- OW->write8(0);
+ OS << '\0';
return true;
}
// ARM mode
@@ -309,21 +313,20 @@ bool ARMAsmBackend::writeNopData(uint64_t Count, MCObjectWriter *OW) const {
hasNOP() ? ARMv6T2_NopEncoding : ARMv4_NopEncoding;
uint64_t NumNops = Count / 4;
for (uint64_t i = 0; i != NumNops; ++i)
- OW->write32(nopEncoding);
+ support::endian::write(OS, nopEncoding, Endian);
// FIXME: should this function return false when unable to write exactly
// 'Count' bytes with NOP encodings?
switch (Count % 4) {
default:
break; // No leftover bytes to write
case 1:
- OW->write8(0);
+ OS << '\0';
break;
case 2:
- OW->write16(0);
+ OS.write("\0\0", 2);
break;
case 3:
- OW->write16(0);
- OW->write8(0xa0);
+ OS.write("\0\0\xa0", 3);
break;
}
@@ -360,7 +363,7 @@ unsigned ARMAsmBackend::adjustFixupValue(const MCAssembler &Asm,
const MCFixup &Fixup,
const MCValue &Target, uint64_t Value,
bool IsResolved, MCContext &Ctx,
- bool IsLittleEndian) const {
+ const MCSubtargetInfo* STI) const {
unsigned Kind = Fixup.getKind();
// MachO tries to make .o files that look vaguely pre-linked, so for MOVW/MOVT
@@ -389,6 +392,7 @@ unsigned ARMAsmBackend::adjustFixupValue(const MCAssembler &Asm,
case FK_SecRel_4:
return Value;
case ARM::fixup_arm_movt_hi16:
+ assert(STI != nullptr);
if (IsResolved || !STI->getTargetTriple().isOSBinFormatELF())
Value >>= 16;
LLVM_FALLTHROUGH;
@@ -401,6 +405,7 @@ unsigned ARMAsmBackend::adjustFixupValue(const MCAssembler &Asm,
return Value;
}
case ARM::fixup_t2_movt_hi16:
+ assert(STI != nullptr);
if (IsResolved || !STI->getTargetTriple().isOSBinFormatELF())
Value >>= 16;
LLVM_FALLTHROUGH;
@@ -414,7 +419,7 @@ unsigned ARMAsmBackend::adjustFixupValue(const MCAssembler &Asm,
// inst{14-12} = Mid3;
// inst{7-0} = Lo8;
Value = (Hi4 << 16) | (i << 26) | (Mid3 << 12) | (Lo8);
- return swapHalfWords(Value, IsLittleEndian);
+ return swapHalfWords(Value, Endian == support::little);
}
case ARM::fixup_arm_ldst_pcrel_12:
// ARM PC-relative values are offset by 8.
@@ -437,7 +442,7 @@ unsigned ARMAsmBackend::adjustFixupValue(const MCAssembler &Asm,
// Same addressing mode as fixup_arm_pcrel_10,
// but with 16-bit halfwords swapped.
if (Kind == ARM::fixup_t2_ldst_pcrel_12)
- return swapHalfWords(Value, IsLittleEndian);
+ return swapHalfWords(Value, Endian == support::little);
return Value;
}
@@ -470,7 +475,7 @@ unsigned ARMAsmBackend::adjustFixupValue(const MCAssembler &Asm,
out |= (Value & 0x700) << 4;
out |= (Value & 0x0FF);
- return swapHalfWords(out, IsLittleEndian);
+ return swapHalfWords(out, Endian == support::little);
}
case ARM::fixup_arm_condbranch:
@@ -487,6 +492,11 @@ unsigned ARMAsmBackend::adjustFixupValue(const MCAssembler &Asm,
return 0xffffff & ((Value - 8) >> 2);
case ARM::fixup_t2_uncondbranch: {
Value = Value - 4;
+ if (!isInt<25>(Value)) {
+ Ctx.reportError(Fixup.getLoc(), "Relocation out of range");
+ return 0;
+ }
+
Value >>= 1; // Low bit is not encoded.
uint32_t out = 0;
@@ -502,10 +512,15 @@ unsigned ARMAsmBackend::adjustFixupValue(const MCAssembler &Asm,
out |= (Value & 0x1FF800) << 5; // imm6 field
out |= (Value & 0x0007FF); // imm11 field
- return swapHalfWords(out, IsLittleEndian);
+ return swapHalfWords(out, Endian == support::little);
}
case ARM::fixup_t2_condbranch: {
Value = Value - 4;
+ if (!isInt<21>(Value)) {
+ Ctx.reportError(Fixup.getLoc(), "Relocation out of range");
+ return 0;
+ }
+
Value >>= 1; // Low bit is not encoded.
uint64_t out = 0;
@@ -515,12 +530,14 @@ unsigned ARMAsmBackend::adjustFixupValue(const MCAssembler &Asm,
out |= (Value & 0x1F800) << 5; // imm6 field
out |= (Value & 0x007FF); // imm11 field
- return swapHalfWords(out, IsLittleEndian);
+ return swapHalfWords(out, Endian == support::little);
}
case ARM::fixup_arm_thumb_bl: {
- // FIXME: We get both thumb1 and thumb2 in here, so we can only check for
- // the less strict thumb2 value.
- if (!isInt<26>(Value - 4)) {
+ if (!isInt<25>(Value - 4) ||
+ (!STI->getFeatureBits()[ARM::FeatureThumb2] &&
+ !STI->getFeatureBits()[ARM::HasV8MBaselineOps] &&
+ !STI->getFeatureBits()[ARM::HasV6MOps] &&
+ !isInt<23>(Value - 4))) {
Ctx.reportError(Fixup.getLoc(), "Relocation out of range");
return 0;
}
@@ -549,7 +566,7 @@ unsigned ARMAsmBackend::adjustFixupValue(const MCAssembler &Asm,
uint32_t FirstHalf = (((uint16_t)signBit << 10) | (uint16_t)imm10Bits);
uint32_t SecondHalf = (((uint16_t)J1Bit << 13) | ((uint16_t)J2Bit << 11) |
(uint16_t)imm11Bits);
- return joinHalfWords(FirstHalf, SecondHalf, IsLittleEndian);
+ return joinHalfWords(FirstHalf, SecondHalf, Endian == support::little);
}
case ARM::fixup_arm_thumb_blx: {
// The value doesn't encode the low two bits (always zero) and is offset by
@@ -585,12 +602,13 @@ unsigned ARMAsmBackend::adjustFixupValue(const MCAssembler &Asm,
uint32_t FirstHalf = (((uint16_t)signBit << 10) | (uint16_t)imm10HBits);
uint32_t SecondHalf = (((uint16_t)J1Bit << 13) | ((uint16_t)J2Bit << 11) |
((uint16_t)imm10LBits) << 1);
- return joinHalfWords(FirstHalf, SecondHalf, IsLittleEndian);
+ return joinHalfWords(FirstHalf, SecondHalf, Endian == support::little);
}
case ARM::fixup_thumb_adr_pcrel_10:
case ARM::fixup_arm_thumb_cp:
// On CPUs supporting Thumb2, this will be relaxed to an ldr.w, otherwise we
// could have an error on our hands.
+ assert(STI != nullptr);
if (!STI->getFeatureBits()[ARM::FeatureThumb2] && IsResolved) {
const char *FixupDiagnostic = reasonForFixupRelaxation(Fixup, Value);
if (FixupDiagnostic) {
@@ -615,6 +633,7 @@ unsigned ARMAsmBackend::adjustFixupValue(const MCAssembler &Asm,
}
case ARM::fixup_arm_thumb_br:
// Offset by 4 and don't encode the lower bit, which is always 0.
+ assert(STI != nullptr);
if (!STI->getFeatureBits()[ARM::FeatureThumb2] &&
!STI->getFeatureBits()[ARM::HasV8MBaselineOps]) {
const char *FixupDiagnostic = reasonForFixupRelaxation(Fixup, Value);
@@ -626,6 +645,7 @@ unsigned ARMAsmBackend::adjustFixupValue(const MCAssembler &Asm,
return ((Value - 4) >> 1) & 0x7ff;
case ARM::fixup_arm_thumb_bcc:
// Offset by 4 and don't encode the lower bit, which is always 0.
+ assert(STI != nullptr);
if (!STI->getFeatureBits()[ARM::FeatureThumb2]) {
const char *FixupDiagnostic = reasonForFixupRelaxation(Fixup, Value);
if (FixupDiagnostic) {
@@ -673,7 +693,7 @@ unsigned ARMAsmBackend::adjustFixupValue(const MCAssembler &Asm,
// Same addressing mode as fixup_arm_pcrel_10, but with 16-bit halfwords
// swapped.
if (Kind == ARM::fixup_t2_pcrel_10)
- return swapHalfWords(Value, IsLittleEndian);
+ return swapHalfWords(Value, Endian == support::little);
return Value;
}
@@ -704,7 +724,7 @@ unsigned ARMAsmBackend::adjustFixupValue(const MCAssembler &Asm,
// Same addressing mode as fixup_arm_pcrel_9, but with 16-bit halfwords
// swapped.
if (Kind == ARM::fixup_t2_pcrel_9)
- return swapHalfWords(Value, IsLittleEndian);
+ return swapHalfWords(Value, Endian == support::little);
return Value;
}
@@ -730,7 +750,7 @@ unsigned ARMAsmBackend::adjustFixupValue(const MCAssembler &Asm,
EncValue |= (Value & 0x800) << 15;
EncValue |= (Value & 0x700) << 4;
EncValue |= (Value & 0xff);
- return swapHalfWords(EncValue, IsLittleEndian);
+ return swapHalfWords(EncValue, Endian == support::little);
}
}
}
@@ -755,7 +775,7 @@ bool ARMAsmBackend::shouldForceRelocation(const MCAssembler &Asm,
// Create relocations for unconditional branches to function symbols with
// different execution mode in ELF binaries.
if (Sym && Sym->isELF()) {
- unsigned Type = dyn_cast<MCSymbolELF>(Sym)->getType();
+ unsigned Type = cast<MCSymbolELF>(Sym)->getType();
if ((Type == ELF::STT_FUNC || Type == ELF::STT_GNU_IFUNC)) {
if (Asm.isThumbFunc(Sym) && (FixupKind == ARM::fixup_arm_uncondbranch))
return true;
@@ -882,11 +902,11 @@ static unsigned getFixupKindContainerSizeBytes(unsigned Kind) {
void ARMAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
const MCValue &Target,
MutableArrayRef<char> Data, uint64_t Value,
- bool IsResolved) const {
+ bool IsResolved,
+ const MCSubtargetInfo* STI) const {
unsigned NumBytes = getFixupKindNumBytes(Fixup.getKind());
MCContext &Ctx = Asm.getContext();
- Value = adjustFixupValue(Asm, Fixup, Target, Value, IsResolved, Ctx,
- IsLittleEndian);
+ Value = adjustFixupValue(Asm, Fixup, Target, Value, IsResolved, Ctx, STI);
if (!Value)
return; // Doesn't change encoding.
@@ -895,7 +915,7 @@ void ARMAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
// Used to point to big endian bytes.
unsigned FullSizeBytes;
- if (!IsLittleEndian) {
+ if (Endian == support::big) {
FullSizeBytes = getFixupKindContainerSizeBytes(Fixup.getKind());
assert((Offset + FullSizeBytes) <= Data.size() && "Invalid fixup size!");
assert(NumBytes <= FullSizeBytes && "Invalid fixup size!");
@@ -905,14 +925,14 @@ void ARMAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
// the fixup value. The Value has been "split up" into the appropriate
// bitfields above.
for (unsigned i = 0; i != NumBytes; ++i) {
- unsigned Idx = IsLittleEndian ? i : (FullSizeBytes - 1 - i);
+ unsigned Idx = Endian == support::little ? i : (FullSizeBytes - 1 - i);
Data[Offset + Idx] |= uint8_t((Value >> (i * 8)) & 0xff);
}
}
namespace CU {
-/// \brief Compact unwind encoding values.
+/// Compact unwind encoding values.
enum CompactUnwindEncodings {
UNWIND_ARM_MODE_MASK = 0x0F000000,
UNWIND_ARM_MODE_FRAME = 0x01000000,
@@ -1153,52 +1173,39 @@ static MachO::CPUSubTypeARM getMachOSubTypeFromArch(StringRef Arch) {
}
}
-MCAsmBackend *llvm::createARMAsmBackend(const Target &T,
- const MCRegisterInfo &MRI,
- const Triple &TheTriple, StringRef CPU,
- const MCTargetOptions &Options,
- bool isLittle) {
+static MCAsmBackend *createARMAsmBackend(const Target &T,
+ const MCSubtargetInfo &STI,
+ const MCRegisterInfo &MRI,
+ const MCTargetOptions &Options,
+ support::endianness Endian) {
+ const Triple &TheTriple = STI.getTargetTriple();
switch (TheTriple.getObjectFormat()) {
default:
llvm_unreachable("unsupported object format");
case Triple::MachO: {
MachO::CPUSubTypeARM CS = getMachOSubTypeFromArch(TheTriple.getArchName());
- return new ARMAsmBackendDarwin(T, TheTriple, MRI, CS);
+ return new ARMAsmBackendDarwin(T, STI, MRI, CS);
}
case Triple::COFF:
assert(TheTriple.isOSWindows() && "non-Windows ARM COFF is not supported");
- return new ARMAsmBackendWinCOFF(T, TheTriple);
+ return new ARMAsmBackendWinCOFF(T, STI);
case Triple::ELF:
assert(TheTriple.isOSBinFormatELF() && "using ELF for non-ELF target");
uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TheTriple.getOS());
- return new ARMAsmBackendELF(T, TheTriple, OSABI, isLittle);
+ return new ARMAsmBackendELF(T, STI, OSABI, Endian);
}
}
MCAsmBackend *llvm::createARMLEAsmBackend(const Target &T,
+ const MCSubtargetInfo &STI,
const MCRegisterInfo &MRI,
- const Triple &TT, StringRef CPU,
const MCTargetOptions &Options) {
- return createARMAsmBackend(T, MRI, TT, CPU, Options, true);
+ return createARMAsmBackend(T, STI, MRI, Options, support::little);
}
MCAsmBackend *llvm::createARMBEAsmBackend(const Target &T,
+ const MCSubtargetInfo &STI,
const MCRegisterInfo &MRI,
- const Triple &TT, StringRef CPU,
const MCTargetOptions &Options) {
- return createARMAsmBackend(T, MRI, TT, CPU, Options, false);
-}
-
-MCAsmBackend *llvm::createThumbLEAsmBackend(const Target &T,
- const MCRegisterInfo &MRI,
- const Triple &TT, StringRef CPU,
- const MCTargetOptions &Options) {
- return createARMAsmBackend(T, MRI, TT, CPU, Options, true);
-}
-
-MCAsmBackend *llvm::createThumbBEAsmBackend(const Target &T,
- const MCRegisterInfo &MRI,
- const Triple &TT, StringRef CPU,
- const MCTargetOptions &Options) {
- return createARMAsmBackend(T, MRI, TT, CPU, Options, false);
+ return createARMAsmBackend(T, STI, MRI, Options, support::big);
}
diff --git a/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.h b/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.h
index 02374966dafe..88c476bf65f4 100644
--- a/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.h
+++ b/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.h
@@ -19,22 +19,24 @@
namespace llvm {
class ARMAsmBackend : public MCAsmBackend {
- const MCSubtargetInfo *STI;
+ // The STI from the target triple the MCAsmBackend was instantiated with
+ // note that MCFragments may have a different local STI that should be
+ // used in preference.
+ const MCSubtargetInfo &STI;
bool isThumbMode; // Currently emitting Thumb code.
- bool IsLittleEndian; // Big or little endian.
public:
- ARMAsmBackend(const Target &T, const Triple &TT, bool IsLittle)
- : MCAsmBackend(), STI(ARM_MC::createARMMCSubtargetInfo(TT, "", "")),
- isThumbMode(TT.getArchName().startswith("thumb")),
- IsLittleEndian(IsLittle) {}
-
- ~ARMAsmBackend() override { delete STI; }
+ ARMAsmBackend(const Target &T, const MCSubtargetInfo &STI,
+ support::endianness Endian)
+ : MCAsmBackend(Endian), STI(STI),
+ isThumbMode(STI.getTargetTriple().isThumb()) {}
unsigned getNumFixupKinds() const override {
return ARM::NumTargetFixupKinds;
}
- bool hasNOP() const { return STI->getFeatureBits()[ARM::HasV6T2Ops]; }
+ // FIXME: this should be calculated per fragment as the STI may be
+ // different.
+ bool hasNOP() const { return STI.getFeatureBits()[ARM::HasV6T2Ops]; }
const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override;
@@ -44,15 +46,17 @@ public:
unsigned adjustFixupValue(const MCAssembler &Asm, const MCFixup &Fixup,
const MCValue &Target, uint64_t Value,
bool IsResolved, MCContext &Ctx,
- bool IsLittleEndian) const;
+ const MCSubtargetInfo *STI) const;
void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
const MCValue &Target, MutableArrayRef<char> Data,
- uint64_t Value, bool IsResolved) const override;
+ uint64_t Value, bool IsResolved,
+ const MCSubtargetInfo *STI) const override;
- unsigned getRelaxedOpcode(unsigned Op) const;
+ unsigned getRelaxedOpcode(unsigned Op, const MCSubtargetInfo &STI) const;
- bool mayNeedRelaxation(const MCInst &Inst) const override;
+ bool mayNeedRelaxation(const MCInst &Inst,
+ const MCSubtargetInfo &STI) const override;
const char *reasonForFixupRelaxation(const MCFixup &Fixup,
uint64_t Value) const;
@@ -64,14 +68,13 @@ public:
void relaxInstruction(const MCInst &Inst, const MCSubtargetInfo &STI,
MCInst &Res) const override;
- bool writeNopData(uint64_t Count, MCObjectWriter *OW) const override;
+ bool writeNopData(raw_ostream &OS, uint64_t Count) const override;
void handleAssemblerFlag(MCAssemblerFlag Flag) override;
unsigned getPointerSize() const { return 4; }
bool isThumb() const { return isThumbMode; }
void setIsThumb(bool it) { isThumbMode = it; }
- bool isLittle() const { return IsLittleEndian; }
};
} // end namespace llvm
diff --git a/lib/Target/ARM/MCTargetDesc/ARMAsmBackendDarwin.h b/lib/Target/ARM/MCTargetDesc/ARMAsmBackendDarwin.h
index f05e3a6f1160..de1bfaf203e4 100644
--- a/lib/Target/ARM/MCTargetDesc/ARMAsmBackendDarwin.h
+++ b/lib/Target/ARM/MCTargetDesc/ARMAsmBackendDarwin.h
@@ -19,14 +19,13 @@ class ARMAsmBackendDarwin : public ARMAsmBackend {
const MCRegisterInfo &MRI;
public:
const MachO::CPUSubTypeARM Subtype;
- ARMAsmBackendDarwin(const Target &T, const Triple &TT,
+ ARMAsmBackendDarwin(const Target &T, const MCSubtargetInfo &STI,
const MCRegisterInfo &MRI, MachO::CPUSubTypeARM st)
- : ARMAsmBackend(T, TT, /* IsLittleEndian */ true), MRI(MRI), Subtype(st) {
- }
+ : ARMAsmBackend(T, STI, support::little), MRI(MRI), Subtype(st) {}
- std::unique_ptr<MCObjectWriter>
- createObjectWriter(raw_pwrite_stream &OS) const override {
- return createARMMachObjectWriter(OS, /*Is64Bit=*/false, MachO::CPU_TYPE_ARM,
+ std::unique_ptr<MCObjectTargetWriter>
+ createObjectTargetWriter() const override {
+ return createARMMachObjectWriter(/*Is64Bit=*/false, MachO::CPU_TYPE_ARM,
Subtype);
}
diff --git a/lib/Target/ARM/MCTargetDesc/ARMAsmBackendELF.h b/lib/Target/ARM/MCTargetDesc/ARMAsmBackendELF.h
index d0f5419a1b0f..86a583b19cf7 100644
--- a/lib/Target/ARM/MCTargetDesc/ARMAsmBackendELF.h
+++ b/lib/Target/ARM/MCTargetDesc/ARMAsmBackendELF.h
@@ -20,13 +20,13 @@ namespace {
class ARMAsmBackendELF : public ARMAsmBackend {
public:
uint8_t OSABI;
- ARMAsmBackendELF(const Target &T, const Triple &TT, uint8_t OSABI,
- bool IsLittle)
- : ARMAsmBackend(T, TT, IsLittle), OSABI(OSABI) {}
+ ARMAsmBackendELF(const Target &T, const MCSubtargetInfo &STI, uint8_t OSABI,
+ support::endianness Endian)
+ : ARMAsmBackend(T, STI, Endian), OSABI(OSABI) {}
- std::unique_ptr<MCObjectWriter>
- createObjectWriter(raw_pwrite_stream &OS) const override {
- return createARMELFObjectWriter(OS, OSABI, isLittle());
+ std::unique_ptr<MCObjectTargetWriter>
+ createObjectTargetWriter() const override {
+ return createARMELFObjectWriter(OSABI);
}
};
}
diff --git a/lib/Target/ARM/MCTargetDesc/ARMAsmBackendWinCOFF.h b/lib/Target/ARM/MCTargetDesc/ARMAsmBackendWinCOFF.h
index 53b9c29446a3..553922d20f43 100644
--- a/lib/Target/ARM/MCTargetDesc/ARMAsmBackendWinCOFF.h
+++ b/lib/Target/ARM/MCTargetDesc/ARMAsmBackendWinCOFF.h
@@ -17,11 +17,11 @@ using namespace llvm;
namespace {
class ARMAsmBackendWinCOFF : public ARMAsmBackend {
public:
- ARMAsmBackendWinCOFF(const Target &T, const Triple &TheTriple)
- : ARMAsmBackend(T, TheTriple, true) {}
- std::unique_ptr<MCObjectWriter>
- createObjectWriter(raw_pwrite_stream &OS) const override {
- return createARMWinCOFFObjectWriter(OS, /*Is64Bit=*/false);
+ ARMAsmBackendWinCOFF(const Target &T, const MCSubtargetInfo &STI)
+ : ARMAsmBackend(T, STI, support::little) {}
+ std::unique_ptr<MCObjectTargetWriter>
+ createObjectTargetWriter() const override {
+ return createARMWinCOFFObjectWriter(/*Is64Bit=*/false);
}
};
}
diff --git a/lib/Target/ARM/MCTargetDesc/ARMBaseInfo.h b/lib/Target/ARM/MCTargetDesc/ARMBaseInfo.h
index c4480e3da505..b918006fe9e3 100644
--- a/lib/Target/ARM/MCTargetDesc/ARMBaseInfo.h
+++ b/lib/Target/ARM/MCTargetDesc/ARMBaseInfo.h
@@ -98,6 +98,20 @@ namespace ARM_MB {
}
} // namespace ARM_MB
+namespace ARM_TSB {
+ enum TraceSyncBOpt {
+ CSYNC = 0
+ };
+
+ inline static const char *TraceSyncBOptToString(unsigned val) {
+ switch (val) {
+ default:
+ llvm_unreachable("Unknown trace synchronization barrier operation");
+ case CSYNC: return "csync";
+ }
+ }
+} // namespace ARM_TSB
+
namespace ARM_ISB {
enum InstSyncBOpt {
RESERVED_0 = 0,
@@ -186,7 +200,8 @@ namespace ARMII {
AddrModeT2_so = 13,
AddrModeT2_pc = 14, // +/- i12 for pc relative data
AddrModeT2_i8s4 = 15, // i8 * 4
- AddrMode_i12 = 16
+ AddrMode_i12 = 16,
+ AddrMode5FP16 = 17 // i8 * 2
};
inline static const char *AddrModeToString(AddrMode addrmode) {
@@ -197,6 +212,7 @@ namespace ARMII {
case AddrMode3: return "AddrMode3";
case AddrMode4: return "AddrMode4";
case AddrMode5: return "AddrMode5";
+ case AddrMode5FP16: return "AddrMode5FP16";
case AddrMode6: return "AddrMode6";
case AddrModeT1_1: return "AddrModeT1_1";
case AddrModeT1_2: return "AddrModeT1_2";
diff --git a/lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp b/lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp
index 3cd52fe1e7eb..dfa339091a7b 100644
--- a/lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp
+++ b/lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp
@@ -236,9 +236,7 @@ unsigned ARMELFObjectWriter::GetRelocTypeInner(const MCValue &Target,
}
}
-std::unique_ptr<MCObjectWriter>
-llvm::createARMELFObjectWriter(raw_pwrite_stream &OS, uint8_t OSABI,
- bool IsLittleEndian) {
- return createELFObjectWriter(llvm::make_unique<ARMELFObjectWriter>(OSABI), OS,
- IsLittleEndian);
+std::unique_ptr<MCObjectTargetWriter>
+llvm::createARMELFObjectWriter(uint8_t OSABI) {
+ return llvm::make_unique<ARMELFObjectWriter>(OSABI);
}
diff --git a/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp b/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp
index d465da1a7bb1..3373d691db50 100644
--- a/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp
+++ b/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp
@@ -33,6 +33,7 @@
#include "llvm/MC/MCFragment.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstPrinter.h"
+#include "llvm/MC/MCObjectWriter.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSection.h"
#include "llvm/MC/MCSectionELF.h"
@@ -441,9 +442,9 @@ public:
friend class ARMTargetELFStreamer;
ARMELFStreamer(MCContext &Context, std::unique_ptr<MCAsmBackend> TAB,
- raw_pwrite_stream &OS, std::unique_ptr<MCCodeEmitter> Emitter,
+ std::unique_ptr<MCObjectWriter> OW, std::unique_ptr<MCCodeEmitter> Emitter,
bool IsThumb)
- : MCELFStreamer(Context, std::move(TAB), OS, std::move(Emitter)),
+ : MCELFStreamer(Context, std::move(TAB), std::move(OW), std::move(Emitter)),
IsThumb(IsThumb) {
EHReset();
}
@@ -512,9 +513,11 @@ public:
assert(IsThumb);
EmitThumbMappingSymbol();
+ // Thumb wide instructions are emitted as a pair of 16-bit words of the
+ // appropriate endianness.
for (unsigned II = 0, IE = Size; II != IE; II = II + 2) {
- const unsigned I0 = LittleEndian ? II + 0 : (Size - II - 1);
- const unsigned I1 = LittleEndian ? II + 1 : (Size - II - 2);
+ const unsigned I0 = LittleEndian ? II + 0 : II + 1;
+ const unsigned I1 = LittleEndian ? II + 1 : II + 0;
Buffer[Size - II - 2] = uint8_t(Inst >> I0 * CHAR_BIT);
Buffer[Size - II - 1] = uint8_t(Inst >> I1 * CHAR_BIT);
}
@@ -856,6 +859,8 @@ void ARMTargetELFStreamer::emitArchDefaultAttributes() {
case ARM::ArchKind::ARMV8A:
case ARM::ArchKind::ARMV8_1A:
case ARM::ArchKind::ARMV8_2A:
+ case ARM::ArchKind::ARMV8_3A:
+ case ARM::ArchKind::ARMV8_4A:
setAttributeItem(CPU_arch_profile, ApplicationProfile, false);
setAttributeItem(ARM_ISA_use, Allowed, false);
setAttributeItem(THUMB_ISA_use, AllowThumb32, false);
@@ -1066,7 +1071,7 @@ void ARMTargetELFStreamer::finishAttributeSection() {
if (Contents.empty())
return;
- std::sort(Contents.begin(), Contents.end(), AttributeItem::LessTag);
+ llvm::sort(Contents.begin(), Contents.end(), AttributeItem::LessTag);
ARMELFStreamer &Streamer = getStreamer();
@@ -1492,10 +1497,10 @@ MCTargetStreamer *createARMObjectTargetStreamer(MCStreamer &S,
MCELFStreamer *createARMELFStreamer(MCContext &Context,
std::unique_ptr<MCAsmBackend> TAB,
- raw_pwrite_stream &OS,
+ std::unique_ptr<MCObjectWriter> OW,
std::unique_ptr<MCCodeEmitter> Emitter,
bool RelaxAll, bool IsThumb) {
- ARMELFStreamer *S = new ARMELFStreamer(Context, std::move(TAB), OS,
+ ARMELFStreamer *S = new ARMELFStreamer(Context, std::move(TAB), std::move(OW),
std::move(Emitter), IsThumb);
// FIXME: This should eventually end up somewhere else where more
// intelligent flag decisions can be made. For now we are just maintaining
diff --git a/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp b/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp
index f1f35f409900..0dab789505d5 100644
--- a/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp
+++ b/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp
@@ -1520,7 +1520,7 @@ unsigned ARMMCCodeEmitter::
getBitfieldInvertedMaskOpValue(const MCInst &MI, unsigned Op,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
- // 10 bits. lower 5 bits are are the lsb of the mask, high five bits are the
+ // 10 bits. lower 5 bits are the lsb of the mask, high five bits are the
// msb of the mask.
const MCOperand &MO = MI.getOperand(Op);
uint32_t v = ~MO.getImm();
diff --git a/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.cpp b/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.cpp
index ae5bc723ee5f..46434007a854 100644
--- a/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.cpp
+++ b/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.cpp
@@ -21,6 +21,7 @@
#include "llvm/MC/MCELFStreamer.h"
#include "llvm/MC/MCInstrAnalysis.h"
#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCObjectWriter.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSubtargetInfo.h"
@@ -140,17 +141,21 @@ std::string ARM_MC::ParseARMTriple(const Triple &TT, StringRef CPU) {
ARMArchFeature = (ARMArchFeature + "+" + ARM::getArchName(ArchID)).str();
if (TT.isThumb()) {
- if (ARMArchFeature.empty())
- ARMArchFeature = "+thumb-mode,+v4t";
- else
- ARMArchFeature += ",+thumb-mode,+v4t";
+ if (!ARMArchFeature.empty())
+ ARMArchFeature += ",";
+ ARMArchFeature += "+thumb-mode,+v4t";
}
if (TT.isOSNaCl()) {
- if (ARMArchFeature.empty())
- ARMArchFeature = "+nacl-trap";
- else
- ARMArchFeature += ",+nacl-trap";
+ if (!ARMArchFeature.empty())
+ ARMArchFeature += ",";
+ ARMArchFeature += "+nacl-trap";
+ }
+
+ if (TT.isOSWindows()) {
+ if (!ARMArchFeature.empty())
+ ARMArchFeature += ",";
+ ARMArchFeature += "+noarm";
}
return ARMArchFeature;
@@ -201,21 +206,21 @@ static MCAsmInfo *createARMMCAsmInfo(const MCRegisterInfo &MRI,
static MCStreamer *createELFStreamer(const Triple &T, MCContext &Ctx,
std::unique_ptr<MCAsmBackend> &&MAB,
- raw_pwrite_stream &OS,
+ std::unique_ptr<MCObjectWriter> &&OW,
std::unique_ptr<MCCodeEmitter> &&Emitter,
bool RelaxAll) {
return createARMELFStreamer(
- Ctx, std::move(MAB), OS, std::move(Emitter), false,
+ Ctx, std::move(MAB), std::move(OW), std::move(Emitter), false,
(T.getArch() == Triple::thumb || T.getArch() == Triple::thumbeb));
}
static MCStreamer *
createARMMachOStreamer(MCContext &Ctx, std::unique_ptr<MCAsmBackend> &&MAB,
- raw_pwrite_stream &OS,
+ std::unique_ptr<MCObjectWriter> &&OW,
std::unique_ptr<MCCodeEmitter> &&Emitter, bool RelaxAll,
bool DWARFMustBeAtTheEnd) {
- return createMachOStreamer(Ctx, std::move(MAB), OS, std::move(Emitter), false,
- DWARFMustBeAtTheEnd);
+ return createMachOStreamer(Ctx, std::move(MAB), std::move(OW),
+ std::move(Emitter), false, DWARFMustBeAtTheEnd);
}
static MCInstPrinter *createARMMCInstPrinter(const Triple &T,
@@ -338,19 +343,12 @@ extern "C" void LLVMInitializeARMTargetMC() {
for (Target *T : {&getTheThumbLETarget(), &getTheThumbBETarget()})
TargetRegistry::RegisterMCInstrAnalysis(*T, createThumbMCInstrAnalysis);
- // Register the MC Code Emitter
- for (Target *T : {&getTheARMLETarget(), &getTheThumbLETarget()})
+ for (Target *T : {&getTheARMLETarget(), &getTheThumbLETarget()}) {
TargetRegistry::RegisterMCCodeEmitter(*T, createARMLEMCCodeEmitter);
- for (Target *T : {&getTheARMBETarget(), &getTheThumbBETarget()})
+ TargetRegistry::RegisterMCAsmBackend(*T, createARMLEAsmBackend);
+ }
+ for (Target *T : {&getTheARMBETarget(), &getTheThumbBETarget()}) {
TargetRegistry::RegisterMCCodeEmitter(*T, createARMBEMCCodeEmitter);
-
- // Register the asm backend.
- TargetRegistry::RegisterMCAsmBackend(getTheARMLETarget(),
- createARMLEAsmBackend);
- TargetRegistry::RegisterMCAsmBackend(getTheARMBETarget(),
- createARMBEAsmBackend);
- TargetRegistry::RegisterMCAsmBackend(getTheThumbLETarget(),
- createThumbLEAsmBackend);
- TargetRegistry::RegisterMCAsmBackend(getTheThumbBETarget(),
- createThumbBEAsmBackend);
+ TargetRegistry::RegisterMCAsmBackend(*T, createARMBEAsmBackend);
+ }
}
diff --git a/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.h b/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.h
index 0fb97e5fee97..3ee004592ac6 100644
--- a/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.h
+++ b/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.h
@@ -25,6 +25,7 @@ class MCCodeEmitter;
class MCContext;
class MCInstrInfo;
class MCInstPrinter;
+class MCObjectTargetWriter;
class MCObjectWriter;
class MCRegisterInfo;
class MCSubtargetInfo;
@@ -68,52 +69,34 @@ MCCodeEmitter *createARMBEMCCodeEmitter(const MCInstrInfo &MCII,
const MCRegisterInfo &MRI,
MCContext &Ctx);
-MCAsmBackend *createARMAsmBackend(const Target &T, const MCRegisterInfo &MRI,
- const Triple &TT, StringRef CPU,
- const MCTargetOptions &Options,
- bool IsLittleEndian);
-
-MCAsmBackend *createARMLEAsmBackend(const Target &T, const MCRegisterInfo &MRI,
- const Triple &TT, StringRef CPU,
+MCAsmBackend *createARMLEAsmBackend(const Target &T, const MCSubtargetInfo &STI,
+ const MCRegisterInfo &MRI,
const MCTargetOptions &Options);
-MCAsmBackend *createARMBEAsmBackend(const Target &T, const MCRegisterInfo &MRI,
- const Triple &TT, StringRef CPU,
+MCAsmBackend *createARMBEAsmBackend(const Target &T, const MCSubtargetInfo &STI,
+ const MCRegisterInfo &MRI,
const MCTargetOptions &Options);
-MCAsmBackend *createThumbLEAsmBackend(const Target &T,
- const MCRegisterInfo &MRI,
- const Triple &TT, StringRef CPU,
- const MCTargetOptions &Options);
-
-MCAsmBackend *createThumbBEAsmBackend(const Target &T,
- const MCRegisterInfo &MRI,
- const Triple &TT, StringRef CPU,
- const MCTargetOptions &Options);
-
// Construct a PE/COFF machine code streamer which will generate a PE/COFF
// object file.
MCStreamer *createARMWinCOFFStreamer(MCContext &Context,
std::unique_ptr<MCAsmBackend> &&MAB,
- raw_pwrite_stream &OS,
+ std::unique_ptr<MCObjectWriter> &&OW,
std::unique_ptr<MCCodeEmitter> &&Emitter,
bool RelaxAll,
bool IncrementalLinkerCompatible);
/// Construct an ELF Mach-O object writer.
-std::unique_ptr<MCObjectWriter> createARMELFObjectWriter(raw_pwrite_stream &OS,
- uint8_t OSABI,
- bool IsLittleEndian);
+std::unique_ptr<MCObjectTargetWriter> createARMELFObjectWriter(uint8_t OSABI);
/// Construct an ARM Mach-O object writer.
-std::unique_ptr<MCObjectWriter> createARMMachObjectWriter(raw_pwrite_stream &OS,
- bool Is64Bit,
- uint32_t CPUType,
- uint32_t CPUSubtype);
+std::unique_ptr<MCObjectTargetWriter>
+createARMMachObjectWriter(bool Is64Bit, uint32_t CPUType,
+ uint32_t CPUSubtype);
/// Construct an ARM PE/COFF object writer.
-std::unique_ptr<MCObjectWriter>
-createARMWinCOFFObjectWriter(raw_pwrite_stream &OS, bool Is64Bit);
+std::unique_ptr<MCObjectTargetWriter>
+createARMWinCOFFObjectWriter(bool Is64Bit);
/// Construct ARM Mach-O relocation info.
MCRelocationInfo *createARMMachORelocationInfo(MCContext &Ctx);
diff --git a/lib/Target/ARM/MCTargetDesc/ARMMachObjectWriter.cpp b/lib/Target/ARM/MCTargetDesc/ARMMachObjectWriter.cpp
index 521ae5337e7a..4b4956e914f2 100644
--- a/lib/Target/ARM/MCTargetDesc/ARMMachObjectWriter.cpp
+++ b/lib/Target/ARM/MCTargetDesc/ARMMachObjectWriter.cpp
@@ -484,10 +484,8 @@ void ARMMachObjectWriter::recordRelocation(MachObjectWriter *Writer,
Writer->addRelocation(RelSymbol, Fragment->getParent(), MRE);
}
-std::unique_ptr<MCObjectWriter>
-llvm::createARMMachObjectWriter(raw_pwrite_stream &OS, bool Is64Bit,
- uint32_t CPUType, uint32_t CPUSubtype) {
- return createMachObjectWriter(
- llvm::make_unique<ARMMachObjectWriter>(Is64Bit, CPUType, CPUSubtype), OS,
- /*IsLittleEndian=*/true);
+std::unique_ptr<MCObjectTargetWriter>
+llvm::createARMMachObjectWriter(bool Is64Bit, uint32_t CPUType,
+ uint32_t CPUSubtype) {
+ return llvm::make_unique<ARMMachObjectWriter>(Is64Bit, CPUType, CPUSubtype);
}
diff --git a/lib/Target/ARM/MCTargetDesc/ARMWinCOFFObjectWriter.cpp b/lib/Target/ARM/MCTargetDesc/ARMWinCOFFObjectWriter.cpp
index 5e09b126f43f..8ae713b7b489 100644
--- a/lib/Target/ARM/MCTargetDesc/ARMWinCOFFObjectWriter.cpp
+++ b/lib/Target/ARM/MCTargetDesc/ARMWinCOFFObjectWriter.cpp
@@ -91,10 +91,9 @@ bool ARMWinCOFFObjectWriter::recordRelocation(const MCFixup &Fixup) const {
namespace llvm {
-std::unique_ptr<MCObjectWriter>
-createARMWinCOFFObjectWriter(raw_pwrite_stream &OS, bool Is64Bit) {
- auto MOTW = llvm::make_unique<ARMWinCOFFObjectWriter>(Is64Bit);
- return createWinCOFFObjectWriter(std::move(MOTW), OS);
+std::unique_ptr<MCObjectTargetWriter>
+createARMWinCOFFObjectWriter(bool Is64Bit) {
+ return llvm::make_unique<ARMWinCOFFObjectWriter>(Is64Bit);
}
} // end namespace llvm
diff --git a/lib/Target/ARM/MCTargetDesc/ARMWinCOFFStreamer.cpp b/lib/Target/ARM/MCTargetDesc/ARMWinCOFFStreamer.cpp
index a2424e1abab3..32cb3dcdcad8 100644
--- a/lib/Target/ARM/MCTargetDesc/ARMWinCOFFStreamer.cpp
+++ b/lib/Target/ARM/MCTargetDesc/ARMWinCOFFStreamer.cpp
@@ -10,6 +10,7 @@
#include "ARMMCTargetDesc.h"
#include "llvm/MC/MCAsmBackend.h"
#include "llvm/MC/MCCodeEmitter.h"
+#include "llvm/MC/MCObjectWriter.h"
#include "llvm/MC/MCWinCOFFStreamer.h"
using namespace llvm;
@@ -18,8 +19,9 @@ namespace {
class ARMWinCOFFStreamer : public MCWinCOFFStreamer {
public:
ARMWinCOFFStreamer(MCContext &C, std::unique_ptr<MCAsmBackend> AB,
- std::unique_ptr<MCCodeEmitter> CE, raw_pwrite_stream &OS)
- : MCWinCOFFStreamer(C, std::move(AB), std::move(CE), OS) {}
+ std::unique_ptr<MCCodeEmitter> CE,
+ std::unique_ptr<MCObjectWriter> OW)
+ : MCWinCOFFStreamer(C, std::move(AB), std::move(CE), std::move(OW)) {}
void EmitAssemblerFlag(MCAssemblerFlag Flag) override;
void EmitThumbFunc(MCSymbol *Symbol) override;
@@ -48,10 +50,11 @@ void ARMWinCOFFStreamer::FinishImpl() {
MCStreamer *llvm::createARMWinCOFFStreamer(
MCContext &Context, std::unique_ptr<MCAsmBackend> &&MAB,
- raw_pwrite_stream &OS, std::unique_ptr<MCCodeEmitter> &&Emitter,
- bool RelaxAll, bool IncrementalLinkerCompatible) {
- auto *S =
- new ARMWinCOFFStreamer(Context, std::move(MAB), std::move(Emitter), OS);
+ std::unique_ptr<MCObjectWriter> &&OW,
+ std::unique_ptr<MCCodeEmitter> &&Emitter, bool RelaxAll,
+ bool IncrementalLinkerCompatible) {
+ auto *S = new ARMWinCOFFStreamer(Context, std::move(MAB), std::move(Emitter),
+ std::move(OW));
S->getAssembler().setIncrementalLinkerCompatible(IncrementalLinkerCompatible);
return S;
}
diff --git a/lib/Target/ARM/MCTargetDesc/CMakeLists.txt b/lib/Target/ARM/MCTargetDesc/CMakeLists.txt
index 9582e8cbef47..cb5742ccc6e3 100644
--- a/lib/Target/ARM/MCTargetDesc/CMakeLists.txt
+++ b/lib/Target/ARM/MCTargetDesc/CMakeLists.txt
@@ -1,7 +1,6 @@
add_llvm_library(LLVMARMDesc
ARMAsmBackend.cpp
ARMELFObjectWriter.cpp
- ARMELFObjectWriter.cpp
ARMELFStreamer.cpp
ARMMachObjectWriter.cpp
ARMMachORelocationInfo.cpp
diff --git a/lib/Target/ARM/MLxExpansionPass.cpp b/lib/Target/ARM/MLxExpansionPass.cpp
index 153e7b1e2197..637e4a44c428 100644
--- a/lib/Target/ARM/MLxExpansionPass.cpp
+++ b/lib/Target/ARM/MLxExpansionPass.cpp
@@ -309,17 +309,17 @@ MLxExpansion::ExpandFPMLxInstruction(MachineBasicBlock &MBB, MachineInstr *MI,
}
MIB.addImm(Pred).addReg(PredReg);
- DEBUG({
- dbgs() << "Expanding: " << *MI;
- dbgs() << " to:\n";
- MachineBasicBlock::iterator MII = MI;
- MII = std::prev(MII);
- MachineInstr &MI2 = *MII;
- MII = std::prev(MII);
- MachineInstr &MI1 = *MII;
- dbgs() << " " << MI1;
- dbgs() << " " << MI2;
- });
+ LLVM_DEBUG({
+ dbgs() << "Expanding: " << *MI;
+ dbgs() << " to:\n";
+ MachineBasicBlock::iterator MII = MI;
+ MII = std::prev(MII);
+ MachineInstr &MI2 = *MII;
+ MII = std::prev(MII);
+ MachineInstr &MI1 = *MII;
+ dbgs() << " " << MI1;
+ dbgs() << " " << MI2;
+ });
MI->eraseFromParent();
++NumExpand;
diff --git a/lib/Target/ARM/README.txt b/lib/Target/ARM/README.txt
index 549af00fcc99..def67cfae727 100644
--- a/lib/Target/ARM/README.txt
+++ b/lib/Target/ARM/README.txt
@@ -502,7 +502,7 @@ those operations and the ARMv6 scalar versions.
//===---------------------------------------------------------------------===//
Split out LDR (literal) from normal ARM LDR instruction. Also consider spliting
-LDR into imm12 and so_reg forms. This allows us to clean up some code. e.g.
+LDR into imm12 and so_reg forms. This allows us to clean up some code. e.g.
ARMLoadStoreOptimizer does not need to look at LDR (literal) and LDR (so_reg)
while ARMConstantIslandPass only need to worry about LDR (literal).
diff --git a/lib/Target/ARM/Thumb1FrameLowering.cpp b/lib/Target/ARM/Thumb1FrameLowering.cpp
index ba00b3d79da9..a65e22fd86e8 100644
--- a/lib/Target/ARM/Thumb1FrameLowering.cpp
+++ b/lib/Target/ARM/Thumb1FrameLowering.cpp
@@ -611,6 +611,12 @@ bool Thumb1FrameLowering::emitPopSpecialFixUp(MachineBasicBlock &MBB,
unsigned TemporaryReg = 0;
BitVector PopFriendly =
TRI.getAllocatableSet(MF, TRI.getRegClass(ARM::tGPRRegClassID));
+ // R7 may be used as a frame pointer, hence marked as not generally
+ // allocatable, however there's no reason to not use it as a temporary for
+ // restoring LR.
+ if (STI.useR7AsFramePointer())
+ PopFriendly.set(ARM::R7);
+
assert(PopFriendly.any() && "No allocatable pop-friendly register?!");
// Rebuild the GPRs from the high registers because they are removed
// form the GPR reg class for thumb1.
@@ -622,17 +628,20 @@ bool Thumb1FrameLowering::emitPopSpecialFixUp(MachineBasicBlock &MBB,
GPRsNoLRSP.reset(ARM::PC);
findTemporariesForLR(GPRsNoLRSP, PopFriendly, UsedRegs, PopReg, TemporaryReg);
- // If we couldn't find a pop-friendly register, restore LR before popping the
- // other callee-saved registers, so we can use one of them as a temporary.
+ // If we couldn't find a pop-friendly register, try restoring LR before
+ // popping the other callee-saved registers, so we could use one of them as a
+ // temporary.
bool UseLDRSP = false;
if (!PopReg && MBBI != MBB.begin()) {
auto PrevMBBI = MBBI;
PrevMBBI--;
if (PrevMBBI->getOpcode() == ARM::tPOP) {
- MBBI = PrevMBBI;
- UsedRegs.stepBackward(*MBBI);
+ UsedRegs.stepBackward(*PrevMBBI);
findTemporariesForLR(GPRsNoLRSP, PopFriendly, UsedRegs, PopReg, TemporaryReg);
- UseLDRSP = true;
+ if (PopReg) {
+ MBBI = PrevMBBI;
+ UseLDRSP = true;
+ }
}
}
diff --git a/lib/Target/ARM/Thumb1InstrInfo.cpp b/lib/Target/ARM/Thumb1InstrInfo.cpp
index 49645834e2de..11aa285fc939 100644
--- a/lib/Target/ARM/Thumb1InstrInfo.cpp
+++ b/lib/Target/ARM/Thumb1InstrInfo.cpp
@@ -109,11 +109,11 @@ loadRegFromStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
unsigned DestReg, int FI,
const TargetRegisterClass *RC,
const TargetRegisterInfo *TRI) const {
- assert((RC == &ARM::tGPRRegClass ||
+ assert((RC->hasSuperClassEq(&ARM::tGPRRegClass) ||
(TargetRegisterInfo::isPhysicalRegister(DestReg) &&
isARMLowRegister(DestReg))) && "Unknown regclass!");
- if (RC == &ARM::tGPRRegClass ||
+ if (RC->hasSuperClassEq(&ARM::tGPRRegClass) ||
(TargetRegisterInfo::isPhysicalRegister(DestReg) &&
isARMLowRegister(DestReg))) {
DebugLoc DL;
@@ -141,3 +141,16 @@ void Thumb1InstrInfo::expandLoadStackGuard(
else
expandLoadStackGuardBase(MI, ARM::tLDRLIT_ga_abs, ARM::tLDRi);
}
+
+bool Thumb1InstrInfo::canCopyGluedNodeDuringSchedule(SDNode *N) const {
+ // In Thumb1 the scheduler may need to schedule a cross-copy between GPRS and CPSR
+ // but this is not always possible there, so allow the Scheduler to clone tADCS and tSBCS
+ // even if they have glue.
+ // FIXME. Actually implement the cross-copy where it is possible (post v6)
+ // because these copies entail more spilling.
+ unsigned Opcode = N->getMachineOpcode();
+ if (Opcode == ARM::tADCS || Opcode == ARM::tSBCS)
+ return true;
+
+ return false;
+}
diff --git a/lib/Target/ARM/Thumb1InstrInfo.h b/lib/Target/ARM/Thumb1InstrInfo.h
index e8d9a9c4ff14..9f04a3ed262f 100644
--- a/lib/Target/ARM/Thumb1InstrInfo.h
+++ b/lib/Target/ARM/Thumb1InstrInfo.h
@@ -53,6 +53,7 @@ public:
const TargetRegisterClass *RC,
const TargetRegisterInfo *TRI) const override;
+ bool canCopyGluedNodeDuringSchedule(SDNode *N) const override;
private:
void expandLoadStackGuard(MachineBasicBlock::iterator MI) const override;
};
diff --git a/lib/Target/ARM/Thumb2ITBlockPass.cpp b/lib/Target/ARM/Thumb2ITBlockPass.cpp
index 04bdd91b53e6..e0a5f7f04fa9 100644
--- a/lib/Target/ARM/Thumb2ITBlockPass.cpp
+++ b/lib/Target/ARM/Thumb2ITBlockPass.cpp
@@ -183,7 +183,7 @@ Thumb2ITBlockPass::MoveCopyOutOfITBlock(MachineInstr *MI,
// If not, then there is nothing to be gained by moving the copy.
MachineBasicBlock::iterator I = MI; ++I;
MachineBasicBlock::iterator E = MI->getParent()->end();
- while (I != E && I->isDebugValue())
+ while (I != E && I->isDebugInstr())
++I;
if (I != E) {
unsigned NPredReg = 0;
@@ -237,7 +237,7 @@ bool Thumb2ITBlockPass::InsertITInstructions(MachineBasicBlock &MBB) {
// block so check the instruction we just put in the block.
for (; MBBI != E && Pos &&
(!MI->isBranch() && !MI->isReturn()) ; ++MBBI) {
- if (MBBI->isDebugValue())
+ if (MBBI->isDebugInstr())
continue;
MachineInstr *NMI = &*MBBI;
diff --git a/lib/Target/ARM/Thumb2InstrInfo.cpp b/lib/Target/ARM/Thumb2InstrInfo.cpp
index c5eb14f3e608..d5f0ba9ee485 100644
--- a/lib/Target/ARM/Thumb2InstrInfo.cpp
+++ b/lib/Target/ARM/Thumb2InstrInfo.cpp
@@ -82,7 +82,7 @@ Thumb2InstrInfo::ReplaceTailWithBranchTo(MachineBasicBlock::iterator Tail,
MachineBasicBlock::iterator E = MBB->begin();
unsigned Count = 4; // At most 4 instructions in an IT block.
while (Count && MBBI != E) {
- if (MBBI->isDebugValue()) {
+ if (MBBI->isDebugInstr()) {
--MBBI;
continue;
}
@@ -109,7 +109,7 @@ Thumb2InstrInfo::ReplaceTailWithBranchTo(MachineBasicBlock::iterator Tail,
bool
Thumb2InstrInfo::isLegalToSplitMBBAt(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI) const {
- while (MBBI->isDebugValue()) {
+ while (MBBI->isDebugInstr()) {
++MBBI;
if (MBBI == MBB.end())
return false;
@@ -489,7 +489,8 @@ bool llvm::rewriteT2FrameIndex(MachineInstr &MI, unsigned FrameRegIdx,
Offset += MI.getOperand(FrameRegIdx+1).getImm();
unsigned PredReg;
- if (Offset == 0 && getInstrPredicate(MI, PredReg) == ARMCC::AL) {
+ if (Offset == 0 && getInstrPredicate(MI, PredReg) == ARMCC::AL &&
+ !MI.definesRegister(ARM::CPSR)) {
// Turn it into a move.
MI.setDesc(TII.get(ARM::tMOVr));
MI.getOperand(FrameRegIdx).ChangeToRegister(FrameReg, false);
@@ -600,6 +601,20 @@ bool llvm::rewriteT2FrameIndex(MachineInstr &MI, unsigned FrameRegIdx,
Offset = -Offset;
isSub = true;
}
+ } else if (AddrMode == ARMII::AddrMode5FP16) {
+ // VFP address mode.
+ const MachineOperand &OffOp = MI.getOperand(FrameRegIdx+1);
+ int InstrOffs = ARM_AM::getAM5FP16Offset(OffOp.getImm());
+ if (ARM_AM::getAM5FP16Op(OffOp.getImm()) == ARM_AM::sub)
+ InstrOffs *= -1;
+ NumBits = 8;
+ Scale = 2;
+ Offset += InstrOffs * 2;
+ assert((Offset & (Scale-1)) == 0 && "Can't encode this offset!");
+ if (Offset < 0) {
+ Offset = -Offset;
+ isSub = true;
+ }
} else if (AddrMode == ARMII::AddrModeT2_i8s4) {
Offset += MI.getOperand(FrameRegIdx + 1).getImm() * 4;
NumBits = 10; // 8 bits scaled by 4
diff --git a/lib/Target/ARM/Thumb2SizeReduction.cpp b/lib/Target/ARM/Thumb2SizeReduction.cpp
index 5357e26856ea..abf54ba7e87c 100644
--- a/lib/Target/ARM/Thumb2SizeReduction.cpp
+++ b/lib/Target/ARM/Thumb2SizeReduction.cpp
@@ -610,7 +610,8 @@ Thumb2SizeReduce::ReduceLoadStore(MachineBasicBlock &MBB, MachineInstr *MI,
// Transfer MI flags.
MIB.setMIFlags(MI->getFlags());
- DEBUG(errs() << "Converted 32-bit: " << *MI << " to 16-bit: " << *MIB);
+ LLVM_DEBUG(errs() << "Converted 32-bit: " << *MI
+ << " to 16-bit: " << *MIB);
MBB.erase_instr(MI);
++NumLdSts;
@@ -657,7 +658,8 @@ Thumb2SizeReduce::ReduceSpecial(MachineBasicBlock &MBB, MachineInstr *MI,
// Transfer MI flags.
MIB.setMIFlags(MI->getFlags());
- DEBUG(errs() << "Converted 32-bit: " << *MI << " to 16-bit: " <<*MIB);
+ LLVM_DEBUG(errs() << "Converted 32-bit: " << *MI
+ << " to 16-bit: " << *MIB);
MBB.erase_instr(MI);
++NumNarrows;
@@ -826,7 +828,8 @@ Thumb2SizeReduce::ReduceTo2Addr(MachineBasicBlock &MBB, MachineInstr *MI,
// Transfer MI flags.
MIB.setMIFlags(MI->getFlags());
- DEBUG(errs() << "Converted 32-bit: " << *MI << " to 16-bit: " << *MIB);
+ LLVM_DEBUG(errs() << "Converted 32-bit: " << *MI
+ << " to 16-bit: " << *MIB);
MBB.erase_instr(MI);
++Num2Addrs;
@@ -933,7 +936,8 @@ Thumb2SizeReduce::ReduceToNarrow(MachineBasicBlock &MBB, MachineInstr *MI,
// Transfer MI flags.
MIB.setMIFlags(MI->getFlags());
- DEBUG(errs() << "Converted 32-bit: " << *MI << " to 16-bit: " << *MIB);
+ LLVM_DEBUG(errs() << "Converted 32-bit: " << *MI
+ << " to 16-bit: " << *MIB);
MBB.erase_instr(MI);
++NumNarrows;
@@ -1033,7 +1037,7 @@ bool Thumb2SizeReduce::ReduceMBB(MachineBasicBlock &MBB) {
BundleMI = MI;
continue;
}
- if (MI->isDebugValue())
+ if (MI->isDebugInstr())
continue;
LiveCPSR = UpdateCPSRUse(*MI, LiveCPSR);
diff --git a/lib/Target/ARM/ThumbRegisterInfo.cpp b/lib/Target/ARM/ThumbRegisterInfo.cpp
index d190edf5913c..e4bdd40fb743 100644
--- a/lib/Target/ARM/ThumbRegisterInfo.cpp
+++ b/lib/Target/ARM/ThumbRegisterInfo.cpp
@@ -475,7 +475,7 @@ bool ThumbRegisterInfo::saveScavengerRegister(
// before that instead and adjust the UseMI.
bool done = false;
for (MachineBasicBlock::iterator II = I; !done && II != UseMI ; ++II) {
- if (II->isDebugValue())
+ if (II->isDebugInstr())
continue;
// If this instruction affects R12, adjust our restore point.
for (unsigned i = 0, e = II->getNumOperands(); i != e; ++i) {
@@ -517,25 +517,13 @@ void ThumbRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
unsigned VReg = 0;
const ARMBaseInstrInfo &TII = *STI.getInstrInfo();
- ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
DebugLoc dl = MI.getDebugLoc();
MachineInstrBuilder MIB(*MBB.getParent(), &MI);
- unsigned FrameReg = ARM::SP;
+ unsigned FrameReg;
int FrameIndex = MI.getOperand(FIOperandNum).getIndex();
- int Offset = MF.getFrameInfo().getObjectOffset(FrameIndex) +
- MF.getFrameInfo().getStackSize() + SPAdj;
-
- if (MF.getFrameInfo().hasVarSizedObjects()) {
- assert(SPAdj == 0 && STI.getFrameLowering()->hasFP(MF) && "Unexpected");
- // There are alloca()'s in this function, must reference off the frame
- // pointer or base pointer instead.
- if (!hasBasePointer(MF)) {
- FrameReg = getFrameRegister(MF);
- Offset -= AFI->getFramePtrSpillOffset();
- } else
- FrameReg = BasePtr;
- }
+ const ARMFrameLowering *TFI = getFrameLowering(MF);
+ int Offset = TFI->ResolveFrameIndexReference(MF, FrameIndex, FrameReg, SPAdj);
// PEI::scavengeFrameVirtualRegs() cannot accurately track SPAdj because the
// call frame setup/destroy instructions have already been eliminated. That
@@ -560,7 +548,7 @@ void ThumbRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
}
// Modify MI as necessary to handle as much of 'Offset' as possible
- assert(AFI->isThumbFunction() &&
+ assert(MF.getInfo<ARMFunctionInfo>()->isThumbFunction() &&
"This eliminateFrameIndex only supports Thumb1!");
if (rewriteFrameIndex(MI, FIOperandNum, FrameReg, Offset, TII))
return;