diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2018-07-28 10:51:19 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2018-07-28 10:51:19 +0000 |
| commit | eb11fae6d08f479c0799db45860a98af528fa6e7 (patch) | |
| tree | 44d492a50c8c1a7eb8e2d17ea3360ec4d066f042 /lib/Target/ARM | |
| parent | b8a2042aa938069e862750553db0e4d82d25822c (diff) | |
Notes
Diffstat (limited to 'lib/Target/ARM')
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; |
